lots of progress
This commit is contained in:
@@ -0,0 +1,83 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use GuzzleHttp\Client;
|
||||||
|
use Illuminate\Support\Facades\Log;
|
||||||
|
|
||||||
|
class IPGeolocationController extends Controller
|
||||||
|
{
|
||||||
|
protected $client;
|
||||||
|
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
$this->client = new Client([
|
||||||
|
'timeout' => 10,
|
||||||
|
'verify' => false
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function index()
|
||||||
|
{
|
||||||
|
return view('ip-geolocation.index');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function lookup(Request $request)
|
||||||
|
{
|
||||||
|
Log::info('IP Lookup request received', ['ip' => $request->ip]);
|
||||||
|
|
||||||
|
$request->validate([
|
||||||
|
'ip' => 'required|ip'
|
||||||
|
]);
|
||||||
|
|
||||||
|
try {
|
||||||
|
Log::info('Making request to IP-API', ['ip' => $request->ip]);
|
||||||
|
|
||||||
|
$response = $this->client->get("http://ip-api.com/json/{$request->ip}");
|
||||||
|
|
||||||
|
Log::info('IP-API response received', [
|
||||||
|
'status' => $response->getStatusCode(),
|
||||||
|
'body' => (string) $response->getBody()
|
||||||
|
]);
|
||||||
|
|
||||||
|
if ($response->getStatusCode() === 200) {
|
||||||
|
$data = json_decode($response->getBody(), true);
|
||||||
|
|
||||||
|
if ($data['status'] === 'success') {
|
||||||
|
return response()->json([
|
||||||
|
'success' => true,
|
||||||
|
'data' => [
|
||||||
|
'country' => $data['country'],
|
||||||
|
'city' => $data['city'],
|
||||||
|
'region' => $data['regionName'],
|
||||||
|
'timezone' => $data['timezone'],
|
||||||
|
'isp' => $data['isp'],
|
||||||
|
'org' => $data['org'],
|
||||||
|
'as' => $data['as'],
|
||||||
|
'latitude' => $data['lat'],
|
||||||
|
'longitude' => $data['lon'],
|
||||||
|
'zip' => $data['zip']
|
||||||
|
]
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return response()->json([
|
||||||
|
'success' => false,
|
||||||
|
'message' => 'Could not find location information for this IP.'
|
||||||
|
], 404);
|
||||||
|
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
Log::error('IP Lookup error', [
|
||||||
|
'ip' => $request->ip,
|
||||||
|
'error' => $e->getMessage()
|
||||||
|
]);
|
||||||
|
|
||||||
|
return response()->json([
|
||||||
|
'success' => false,
|
||||||
|
'message' => 'An error occurred while looking up the IP: ' . $e->getMessage()
|
||||||
|
], 500);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,60 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
|
use App\Models\Proxy;
|
||||||
|
use Illuminate\Http\Response;
|
||||||
|
|
||||||
|
class PacFileController extends Controller
|
||||||
|
{
|
||||||
|
public function generate()
|
||||||
|
{
|
||||||
|
// Get active proxies from the database
|
||||||
|
$proxies = Proxy::where('is_active', true)
|
||||||
|
->orderBy('score', 'desc')
|
||||||
|
->limit(10)
|
||||||
|
->get();
|
||||||
|
|
||||||
|
// Generate PAC file content
|
||||||
|
$pacContent = $this->generatePacContent($proxies);
|
||||||
|
|
||||||
|
// Return the PAC file with proper headers
|
||||||
|
return response($pacContent)
|
||||||
|
->header('Content-Type', 'application/x-ns-proxy-autoconfig')
|
||||||
|
->header('Content-Disposition', 'attachment; filename="proxy.pac"');
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function generatePacContent($proxies)
|
||||||
|
{
|
||||||
|
// Start with the PAC file header
|
||||||
|
$content = "function FindProxyForURL(url, host) {\n";
|
||||||
|
$content .= " // List of proxy servers\n";
|
||||||
|
$content .= " var proxyList = [\n";
|
||||||
|
|
||||||
|
// Add proxy servers to the list
|
||||||
|
foreach ($proxies as $proxy) {
|
||||||
|
$content .= " 'PROXY {$proxy->ip}:{$proxy->port}',\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add fallback to DIRECT if no proxies are available
|
||||||
|
$content .= " 'DIRECT'\n";
|
||||||
|
$content .= " ];\n\n";
|
||||||
|
|
||||||
|
// Add proxy selection logic
|
||||||
|
$content .= " // Don't proxy localhost\n";
|
||||||
|
$content .= " if (isPlainHostName(host) ||\n";
|
||||||
|
$content .= " shExpMatch(host, '*.local') ||\n";
|
||||||
|
$content .= " isInNet(dnsResolve(host), '10.0.0.0', '255.0.0.0') ||\n";
|
||||||
|
$content .= " isInNet(dnsResolve(host), '172.16.0.0', '255.240.0.0') ||\n";
|
||||||
|
$content .= " isInNet(dnsResolve(host), '192.168.0.0', '255.255.0.0') ||\n";
|
||||||
|
$content .= " isInNet(dnsResolve(host), '127.0.0.0', '255.0.0.0'))\n";
|
||||||
|
$content .= " return 'DIRECT';\n\n";
|
||||||
|
|
||||||
|
// Add proxy selection based on URL
|
||||||
|
$content .= " // Use proxy for all other URLs\n";
|
||||||
|
$content .= " return proxyList.join('; ');\n";
|
||||||
|
$content .= "}\n";
|
||||||
|
|
||||||
|
return $content;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,79 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
|
use App\Services\ProxyService;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use GuzzleHttp\Client;
|
||||||
|
use GuzzleHttp\Exception\RequestException;
|
||||||
|
|
||||||
|
class ProxyCheckerController extends Controller
|
||||||
|
{
|
||||||
|
protected $proxyService;
|
||||||
|
|
||||||
|
public function __construct(ProxyService $proxyService)
|
||||||
|
{
|
||||||
|
$this->proxyService = $proxyService;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function index()
|
||||||
|
{
|
||||||
|
return view('proxy-checker.index');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function check(Request $request)
|
||||||
|
{
|
||||||
|
$request->validate([
|
||||||
|
'ip' => 'required|ip',
|
||||||
|
'port' => 'required|integer|min:1|max:65535',
|
||||||
|
'type' => 'required|in:http,https,socks4,socks5',
|
||||||
|
'test_url' => 'required|url'
|
||||||
|
]);
|
||||||
|
|
||||||
|
$proxy = [
|
||||||
|
'ip' => $request->ip,
|
||||||
|
'port' => $request->port,
|
||||||
|
'type' => $request->type,
|
||||||
|
'url' => $request->test_url
|
||||||
|
];
|
||||||
|
|
||||||
|
try {
|
||||||
|
$client = new Client([
|
||||||
|
'timeout' => 10,
|
||||||
|
'verify' => false,
|
||||||
|
'proxy' => [
|
||||||
|
'http' => "{$proxy['type']}://{$proxy['ip']}:{$proxy['port']}",
|
||||||
|
'https' => "{$proxy['type']}://{$proxy['ip']}:{$proxy['port']}"
|
||||||
|
]
|
||||||
|
]);
|
||||||
|
|
||||||
|
$startTime = microtime(true);
|
||||||
|
$response = $client->get($proxy['url']);
|
||||||
|
$endTime = microtime(true);
|
||||||
|
|
||||||
|
$speed = round(($endTime - $startTime) * 1000, 2); // Convert to milliseconds
|
||||||
|
|
||||||
|
return response()->json([
|
||||||
|
'success' => true,
|
||||||
|
'message' => 'Proxy is working!',
|
||||||
|
'data' => [
|
||||||
|
'status_code' => $response->getStatusCode(),
|
||||||
|
'speed' => $speed,
|
||||||
|
'headers' => $response->getHeaders(),
|
||||||
|
'content_type' => $response->getHeaderLine('Content-Type')
|
||||||
|
]
|
||||||
|
]);
|
||||||
|
} catch (RequestException $e) {
|
||||||
|
return response()->json([
|
||||||
|
'success' => false,
|
||||||
|
'message' => 'Proxy check failed: ' . $e->getMessage(),
|
||||||
|
'error' => $e->getCode()
|
||||||
|
], 400);
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
return response()->json([
|
||||||
|
'success' => false,
|
||||||
|
'message' => 'An error occurred: ' . $e->getMessage()
|
||||||
|
], 500);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,12 +2,61 @@
|
|||||||
|
|
||||||
namespace App\Http\Controllers;
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
|
use App\Models\Subscription;
|
||||||
|
use App\Models\UserSubscription;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
|
use Illuminate\Support\Facades\Auth;
|
||||||
|
|
||||||
class SubscriptionController extends Controller
|
class SubscriptionController extends Controller
|
||||||
{
|
{
|
||||||
public function index()
|
public function index()
|
||||||
{
|
{
|
||||||
return view('subscriptions.index');
|
$subscriptions = Subscription::where('is_active', true)->get();
|
||||||
|
$userSubscription = Auth::user()->subscriptions()->where('status', 'active')->first();
|
||||||
|
|
||||||
|
return view('subscriptions.index', compact('subscriptions', 'userSubscription'));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function subscribe(Request $request, Subscription $subscription)
|
||||||
|
{
|
||||||
|
// Check if user already has an active subscription
|
||||||
|
$activeSubscription = Auth::user()->subscriptions()
|
||||||
|
->where('status', 'active')
|
||||||
|
->where('expires_at', '>', now())
|
||||||
|
->first();
|
||||||
|
|
||||||
|
if ($activeSubscription) {
|
||||||
|
return back()->with('error', 'You already have an active subscription.');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create new subscription
|
||||||
|
$userSubscription = UserSubscription::create([
|
||||||
|
'user_id' => Auth::id(),
|
||||||
|
'subscription_id' => $subscription->id,
|
||||||
|
'started_at' => now(),
|
||||||
|
'expires_at' => now()->addDays($subscription->duration_days),
|
||||||
|
'status' => 'active'
|
||||||
|
]);
|
||||||
|
|
||||||
|
// Here you would typically integrate with a payment processor
|
||||||
|
// For now, we'll just create the subscription
|
||||||
|
|
||||||
|
return redirect()->route('subscriptions.index')
|
||||||
|
->with('success', 'Successfully subscribed to ' . $subscription->name . ' plan!');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function cancel(UserSubscription $userSubscription)
|
||||||
|
{
|
||||||
|
if ($userSubscription->user_id !== Auth::id()) {
|
||||||
|
return back()->with('error', 'Unauthorized action.');
|
||||||
|
}
|
||||||
|
|
||||||
|
$userSubscription->update([
|
||||||
|
'status' => 'cancelled',
|
||||||
|
'expires_at' => now()
|
||||||
|
]);
|
||||||
|
|
||||||
|
return redirect()->route('subscriptions.index')
|
||||||
|
->with('success', 'Subscription cancelled successfully.');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
class Subscription extends Model
|
||||||
|
{
|
||||||
|
use HasFactory;
|
||||||
|
|
||||||
|
protected $fillable = [
|
||||||
|
'name',
|
||||||
|
'description',
|
||||||
|
'price',
|
||||||
|
'duration_days',
|
||||||
|
'features',
|
||||||
|
'min_score',
|
||||||
|
'verification_interval_minutes',
|
||||||
|
'is_active'
|
||||||
|
];
|
||||||
|
|
||||||
|
protected $casts = [
|
||||||
|
'features' => 'array',
|
||||||
|
'is_active' => 'boolean',
|
||||||
|
'price' => 'decimal:2',
|
||||||
|
'duration_days' => 'integer',
|
||||||
|
'min_score' => 'integer',
|
||||||
|
'verification_interval_minutes' => 'integer'
|
||||||
|
];
|
||||||
|
|
||||||
|
public function users()
|
||||||
|
{
|
||||||
|
return $this->hasMany(UserSubscription::class);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -45,4 +45,17 @@ class User extends Authenticatable
|
|||||||
'password' => 'hashed',
|
'password' => 'hashed',
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function subscriptions()
|
||||||
|
{
|
||||||
|
return $this->hasMany(UserSubscription::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function activeSubscription()
|
||||||
|
{
|
||||||
|
return $this->subscriptions()
|
||||||
|
->where('status', 'active')
|
||||||
|
->where('expires_at', '>', now())
|
||||||
|
->first();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,40 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
class UserSubscription extends Model
|
||||||
|
{
|
||||||
|
use HasFactory;
|
||||||
|
|
||||||
|
protected $fillable = [
|
||||||
|
'user_id',
|
||||||
|
'subscription_id',
|
||||||
|
'started_at',
|
||||||
|
'expires_at',
|
||||||
|
'status',
|
||||||
|
'payment_id'
|
||||||
|
];
|
||||||
|
|
||||||
|
protected $casts = [
|
||||||
|
'started_at' => 'datetime',
|
||||||
|
'expires_at' => 'datetime'
|
||||||
|
];
|
||||||
|
|
||||||
|
public function user()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(User::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function subscription()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(Subscription::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function isActive()
|
||||||
|
{
|
||||||
|
return $this->status === 'active' && $this->expires_at->isFuture();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
return new class extends Migration
|
||||||
|
{
|
||||||
|
public function up()
|
||||||
|
{
|
||||||
|
Schema::create('subscriptions', function (Blueprint $table) {
|
||||||
|
$table->id();
|
||||||
|
$table->string('name');
|
||||||
|
$table->text('description');
|
||||||
|
$table->decimal('price', 10, 2);
|
||||||
|
$table->integer('duration_days');
|
||||||
|
$table->json('features');
|
||||||
|
$table->integer('min_score');
|
||||||
|
$table->integer('verification_interval_minutes');
|
||||||
|
$table->boolean('is_active')->default(true);
|
||||||
|
$table->timestamps();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public function down()
|
||||||
|
{
|
||||||
|
Schema::dropIfExists('subscriptions');
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
return new class extends Migration
|
||||||
|
{
|
||||||
|
public function up()
|
||||||
|
{
|
||||||
|
Schema::create('user_subscriptions', function (Blueprint $table) {
|
||||||
|
$table->id();
|
||||||
|
$table->foreignId('user_id')->constrained()->onDelete('cascade');
|
||||||
|
$table->foreignId('subscription_id')->constrained()->onDelete('cascade');
|
||||||
|
$table->timestamp('started_at');
|
||||||
|
$table->timestamp('expires_at');
|
||||||
|
$table->string('status')->default('active');
|
||||||
|
$table->string('payment_id')->nullable();
|
||||||
|
$table->timestamps();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public function down()
|
||||||
|
{
|
||||||
|
Schema::dropIfExists('user_subscriptions');
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -0,0 +1,67 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Database\Seeders;
|
||||||
|
|
||||||
|
use App\Models\Subscription;
|
||||||
|
use Illuminate\Database\Seeder;
|
||||||
|
|
||||||
|
class SubscriptionSeeder extends Seeder
|
||||||
|
{
|
||||||
|
public function run()
|
||||||
|
{
|
||||||
|
$subscriptions = [
|
||||||
|
[
|
||||||
|
'name' => 'Free',
|
||||||
|
'description' => 'Basic access to free proxies',
|
||||||
|
'price' => 0,
|
||||||
|
'duration_days' => 30,
|
||||||
|
'features' => [
|
||||||
|
'Access to basic proxies',
|
||||||
|
'Standard verification interval',
|
||||||
|
'Basic support'
|
||||||
|
],
|
||||||
|
'min_score' => 50,
|
||||||
|
'verification_interval_minutes' => 60,
|
||||||
|
'is_active' => true
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'name' => 'Pro',
|
||||||
|
'description' => 'Enhanced access to high-quality proxies',
|
||||||
|
'price' => 9.99,
|
||||||
|
'duration_days' => 30,
|
||||||
|
'features' => [
|
||||||
|
'Access to premium proxies',
|
||||||
|
'Faster verification interval',
|
||||||
|
'Priority support',
|
||||||
|
'Higher minimum score',
|
||||||
|
'API access'
|
||||||
|
],
|
||||||
|
'min_score' => 80,
|
||||||
|
'verification_interval_minutes' => 30,
|
||||||
|
'is_active' => true
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'name' => 'Enterprise',
|
||||||
|
'description' => 'Full access to all premium features',
|
||||||
|
'price' => 29.99,
|
||||||
|
'duration_days' => 30,
|
||||||
|
'features' => [
|
||||||
|
'Access to all proxies',
|
||||||
|
'Fastest verification interval',
|
||||||
|
'24/7 priority support',
|
||||||
|
'Highest minimum score',
|
||||||
|
'API access',
|
||||||
|
'Custom proxy filtering',
|
||||||
|
'Dedicated support'
|
||||||
|
],
|
||||||
|
'min_score' => 90,
|
||||||
|
'verification_interval_minutes' => 15,
|
||||||
|
'is_active' => true
|
||||||
|
]
|
||||||
|
];
|
||||||
|
|
||||||
|
foreach ($subscriptions as $subscription) {
|
||||||
|
Subscription::create($subscription);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,161 @@
|
|||||||
|
@extends('layouts.app')
|
||||||
|
|
||||||
|
@section('content')
|
||||||
|
<div class="container py-5">
|
||||||
|
<div class="row justify-content-center">
|
||||||
|
<div class="col-lg-8">
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-header">
|
||||||
|
<h5 class="card-title mb-0">IP Geolocation Lookup</h5>
|
||||||
|
</div>
|
||||||
|
<div class="card-body">
|
||||||
|
<form id="ipLookupForm">
|
||||||
|
@csrf
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="ip" class="form-label">IP Address</label>
|
||||||
|
<div class="input-group">
|
||||||
|
<input type="text" class="form-control" id="ip" name="ip" required placeholder="e.g., 8.8.8.8">
|
||||||
|
<button type="submit" class="btn btn-primary">
|
||||||
|
<i class="bi bi-search me-2"></i>Lookup
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
<div id="results" class="mt-4" style="display: none;">
|
||||||
|
<h6 class="mb-3">Location Information</h6>
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-body">
|
||||||
|
<div id="resultContent"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="loading" class="mt-4 text-center" style="display: none;">
|
||||||
|
<div class="spinner-border text-primary" role="status">
|
||||||
|
<span class="visually-hidden">Loading...</span>
|
||||||
|
</div>
|
||||||
|
<p class="mt-2">Looking up IP address...</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
@push('scripts')
|
||||||
|
<script>
|
||||||
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
|
const form = document.getElementById('ipLookupForm');
|
||||||
|
const results = document.getElementById('results');
|
||||||
|
const resultContent = document.getElementById('resultContent');
|
||||||
|
const loading = document.getElementById('loading');
|
||||||
|
|
||||||
|
form.addEventListener('submit', async function(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
|
||||||
|
// Show loading, hide results
|
||||||
|
loading.style.display = 'block';
|
||||||
|
results.style.display = 'none';
|
||||||
|
|
||||||
|
try {
|
||||||
|
console.log('Submitting form with IP:', form.ip.value);
|
||||||
|
|
||||||
|
const response = await fetch('{{ route("ip-geolocation.lookup") }}', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
'X-CSRF-TOKEN': document.querySelector('meta[name="csrf-token"]').content
|
||||||
|
},
|
||||||
|
body: JSON.stringify({
|
||||||
|
ip: form.ip.value
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log('Response status:', response.status);
|
||||||
|
const data = await response.json();
|
||||||
|
console.log('Response data:', data);
|
||||||
|
|
||||||
|
// Hide loading
|
||||||
|
loading.style.display = 'none';
|
||||||
|
|
||||||
|
// Show results
|
||||||
|
results.style.display = 'block';
|
||||||
|
|
||||||
|
if (data.success) {
|
||||||
|
resultContent.innerHTML = `
|
||||||
|
<div class="alert alert-success">
|
||||||
|
<i class="bi bi-check-circle-fill me-2"></i>Location information found
|
||||||
|
</div>
|
||||||
|
<div class="table-responsive">
|
||||||
|
<table class="table table-sm">
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<th>Country:</th>
|
||||||
|
<td>${data.data.country}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th>City:</th>
|
||||||
|
<td>${data.data.city}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th>Region:</th>
|
||||||
|
<td>${data.data.region}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th>Timezone:</th>
|
||||||
|
<td>${data.data.timezone}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th>ISP:</th>
|
||||||
|
<td>${data.data.isp}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th>Organization:</th>
|
||||||
|
<td>${data.data.org}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th>AS:</th>
|
||||||
|
<td>${data.data.as}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th>Coordinates:</th>
|
||||||
|
<td>${data.data.latitude}, ${data.data.longitude}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th>ZIP Code:</th>
|
||||||
|
<td>${data.data.zip}</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
<div class="mt-3">
|
||||||
|
<a href="https://www.google.com/maps?q=${data.data.latitude},${data.data.longitude}"
|
||||||
|
target="_blank"
|
||||||
|
class="btn btn-outline-primary btn-sm">
|
||||||
|
<i class="bi bi-geo-alt me-2"></i>View on Google Maps
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
} else {
|
||||||
|
resultContent.innerHTML = `
|
||||||
|
<div class="alert alert-danger">
|
||||||
|
<i class="bi bi-x-circle-fill me-2"></i>${data.message}
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error:', error);
|
||||||
|
loading.style.display = 'none';
|
||||||
|
results.style.display = 'block';
|
||||||
|
resultContent.innerHTML = `
|
||||||
|
<div class="alert alert-danger">
|
||||||
|
<i class="bi bi-x-circle-fill me-2"></i>An error occurred while looking up the IP address: ${error.message}
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
@endpush
|
||||||
|
@endsection
|
||||||
@@ -29,6 +29,21 @@
|
|||||||
{{ __('Port Scanner') }}
|
{{ __('Port Scanner') }}
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link {{ request()->routeIs('proxy-checker.index') ? 'active' : '' }}" href="{{ route('proxy-checker.index') }}">
|
||||||
|
{{ __('Proxy Checker') }}
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link {{ request()->routeIs('ip-geolocation.index') ? 'active' : '' }}" href="{{ route('ip-geolocation.index') }}">
|
||||||
|
{{ __('IP Lookup') }}
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link {{ request()->routeIs('pac.file') ? 'active' : '' }}" href="{{ route('pac.file') }}">
|
||||||
|
{{ __('PAC File') }}
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
<li class="nav-item">
|
<li class="nav-item">
|
||||||
<a class="nav-link {{ request()->routeIs('subscriptions.index') ? 'active' : '' }}" href="{{ route('subscriptions.index') }}">
|
<a class="nav-link {{ request()->routeIs('subscriptions.index') ? 'active' : '' }}" href="{{ route('subscriptions.index') }}">
|
||||||
{{ __('Subscriptions') }}
|
{{ __('Subscriptions') }}
|
||||||
|
|||||||
@@ -0,0 +1,151 @@
|
|||||||
|
@extends('layouts.app')
|
||||||
|
|
||||||
|
@section('content')
|
||||||
|
<div class="container py-5">
|
||||||
|
<div class="row justify-content-center">
|
||||||
|
<div class="col-lg-8">
|
||||||
|
<div class="card shadow-sm">
|
||||||
|
<div class="card-body p-4">
|
||||||
|
<div class="text-center mb-4">
|
||||||
|
<i class="bi bi-gear-wide-connected display-4 text-primary mb-3"></i>
|
||||||
|
<h1 class="h3 mb-2">Proxy Auto-Configuration (PAC) File</h1>
|
||||||
|
<p class="text-muted">Configure your browser to automatically use our proxy servers</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mb-4">
|
||||||
|
<h2 class="h5 mb-3">What is a PAC File?</h2>
|
||||||
|
<p>A Proxy Auto-Configuration (PAC) file is a JavaScript file that defines how web browsers and other user agents can automatically choose the appropriate proxy server (access method) for fetching a given URL.</p>
|
||||||
|
<p>Our PAC file automatically selects the best proxy server from our database based on their performance scores.</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mb-4">
|
||||||
|
<h2 class="h5 mb-3">Your PAC File URL</h2>
|
||||||
|
<div class="card mb-4">
|
||||||
|
<div class="card-body">
|
||||||
|
<p class="mb-3">Use this URL in any browser to configure automatic proxy settings:</p>
|
||||||
|
<div class="input-group">
|
||||||
|
<input type="text" class="form-control" id="pacUrl" value="{{ route('pac.generate') }}" readonly>
|
||||||
|
<button class="btn btn-outline-primary" type="button" onclick="copyToClipboard('pacUrl')">
|
||||||
|
<i class="bi bi-clipboard"></i>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h2 class="h5 mb-3">How to Configure Your Browser</h2>
|
||||||
|
|
||||||
|
<!-- Firefox Instructions -->
|
||||||
|
<div class="card mb-3">
|
||||||
|
<div class="card-header bg-light">
|
||||||
|
<i class="bi bi-firefox me-2"></i>Firefox
|
||||||
|
</div>
|
||||||
|
<div class="card-body">
|
||||||
|
<ol class="list-group list-group-numbered mb-3">
|
||||||
|
<li class="list-group-item">Open Firefox Settings (Menu → Settings)</li>
|
||||||
|
<li class="list-group-item">Scroll down to "Network Settings"</li>
|
||||||
|
<li class="list-group-item">Click "Settings..."</li>
|
||||||
|
<li class="list-group-item">Select "Automatic proxy configuration URL"</li>
|
||||||
|
<li class="list-group-item">Paste the PAC URL from above</li>
|
||||||
|
</ol>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Chrome Instructions -->
|
||||||
|
<div class="card mb-3">
|
||||||
|
<div class="card-header bg-light">
|
||||||
|
<i class="bi bi-google-chrome me-2"></i>Chrome
|
||||||
|
</div>
|
||||||
|
<div class="card-body">
|
||||||
|
<ol class="list-group list-group-numbered mb-3">
|
||||||
|
<li class="list-group-item">Open Chrome Settings (Menu → Settings)</li>
|
||||||
|
<li class="list-group-item">Click on "Advanced" to expand settings</li>
|
||||||
|
<li class="list-group-item">Under "System", click "Open your computer's proxy settings"</li>
|
||||||
|
<li class="list-group-item">In Windows: Select "Automatic proxy setup" and paste the PAC URL</li>
|
||||||
|
<li class="list-group-item">In macOS: Select "Automatic Proxy Configuration" and paste the PAC URL</li>
|
||||||
|
</ol>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Safari Instructions -->
|
||||||
|
<div class="card mb-3">
|
||||||
|
<div class="card-header bg-light">
|
||||||
|
<i class="bi bi-safari me-2"></i>Safari
|
||||||
|
</div>
|
||||||
|
<div class="card-body">
|
||||||
|
<ol class="list-group list-group-numbered mb-3">
|
||||||
|
<li class="list-group-item">Open Safari Preferences (Safari → Preferences)</li>
|
||||||
|
<li class="list-group-item">Click on "Advanced" tab</li>
|
||||||
|
<li class="list-group-item">Click "Change Settings..." next to "Proxies"</li>
|
||||||
|
<li class="list-group-item">Select "Automatic Proxy Configuration"</li>
|
||||||
|
<li class="list-group-item">Paste the PAC URL in the field</li>
|
||||||
|
</ol>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Edge Instructions -->
|
||||||
|
<div class="card mb-3">
|
||||||
|
<div class="card-header bg-light">
|
||||||
|
<i class="bi bi-edge me-2"></i>Microsoft Edge
|
||||||
|
</div>
|
||||||
|
<div class="card-body">
|
||||||
|
<ol class="list-group list-group-numbered mb-3">
|
||||||
|
<li class="list-group-item">Open Edge Settings (Menu → Settings)</li>
|
||||||
|
<li class="list-group-item">Click on "System and performance"</li>
|
||||||
|
<li class="list-group-item">Click "Open your computer's proxy settings"</li>
|
||||||
|
<li class="list-group-item">In Windows: Select "Automatic proxy setup" and paste the PAC URL</li>
|
||||||
|
</ol>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mb-4">
|
||||||
|
<h2 class="h5 mb-3">Features of Our PAC File</h2>
|
||||||
|
<ul class="list-group">
|
||||||
|
<li class="list-group-item">
|
||||||
|
<i class="bi bi-check-circle-fill text-success me-2"></i>
|
||||||
|
Automatically selects the best performing proxy servers
|
||||||
|
</li>
|
||||||
|
<li class="list-group-item">
|
||||||
|
<i class="bi bi-check-circle-fill text-success me-2"></i>
|
||||||
|
Bypasses proxy for localhost and local network addresses
|
||||||
|
</li>
|
||||||
|
<li class="list-group-item">
|
||||||
|
<i class="bi bi-check-circle-fill text-success me-2"></i>
|
||||||
|
Updates automatically as proxy performance changes
|
||||||
|
</li>
|
||||||
|
<li class="list-group-item">
|
||||||
|
<i class="bi bi-check-circle-fill text-success me-2"></i>
|
||||||
|
Fallback to direct connection if no proxies are available
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="text-center">
|
||||||
|
<a href="{{ route('pac.generate') }}" class="btn btn-primary">
|
||||||
|
<i class="bi bi-download me-2"></i>Download PAC File
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
@push('scripts')
|
||||||
|
<script>
|
||||||
|
function copyToClipboard(elementId) {
|
||||||
|
const element = document.getElementById(elementId);
|
||||||
|
element.select();
|
||||||
|
document.execCommand('copy');
|
||||||
|
|
||||||
|
// Show feedback
|
||||||
|
const button = element.nextElementSibling;
|
||||||
|
const originalContent = button.innerHTML;
|
||||||
|
button.innerHTML = '<i class="bi bi-check"></i>';
|
||||||
|
setTimeout(() => {
|
||||||
|
button.innerHTML = originalContent;
|
||||||
|
}, 2000);
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
@endpush
|
||||||
|
@endsection
|
||||||
@@ -0,0 +1,146 @@
|
|||||||
|
@extends('layouts.app')
|
||||||
|
|
||||||
|
@section('content')
|
||||||
|
<div class="container py-5">
|
||||||
|
<div class="row justify-content-center">
|
||||||
|
<div class="col-lg-8">
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-header">
|
||||||
|
<h5 class="card-title mb-0">Proxy Checker</h5>
|
||||||
|
</div>
|
||||||
|
<div class="card-body">
|
||||||
|
<form id="proxyCheckForm">
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="ip" class="form-label">Proxy IP Address</label>
|
||||||
|
<input type="text" class="form-control" id="ip" name="ip" required placeholder="e.g., 192.168.1.1">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="port" class="form-label">Port</label>
|
||||||
|
<input type="number" class="form-control" id="port" name="port" required placeholder="e.g., 8080" min="1" max="65535">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="type" class="form-label">Proxy Type</label>
|
||||||
|
<select class="form-select" id="type" name="type" required>
|
||||||
|
<option value="http">HTTP</option>
|
||||||
|
<option value="https">HTTPS</option>
|
||||||
|
<option value="socks4">SOCKS4</option>
|
||||||
|
<option value="socks5">SOCKS5</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="test_url" class="form-label">Test URL</label>
|
||||||
|
<input type="url" class="form-control" id="test_url" name="test_url" required placeholder="e.g., https://example.com" value="https://example.com">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<button type="submit" class="btn btn-primary">
|
||||||
|
<i class="bi bi-search me-2"></i>Check Proxy
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
<div id="results" class="mt-4" style="display: none;">
|
||||||
|
<h6 class="mb-3">Test Results</h6>
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-body">
|
||||||
|
<div id="resultContent"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="loading" class="mt-4 text-center" style="display: none;">
|
||||||
|
<div class="spinner-border text-primary" role="status">
|
||||||
|
<span class="visually-hidden">Loading...</span>
|
||||||
|
</div>
|
||||||
|
<p class="mt-2">Checking proxy...</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
@push('scripts')
|
||||||
|
<script>
|
||||||
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
|
const form = document.getElementById('proxyCheckForm');
|
||||||
|
const results = document.getElementById('results');
|
||||||
|
const resultContent = document.getElementById('resultContent');
|
||||||
|
const loading = document.getElementById('loading');
|
||||||
|
|
||||||
|
form.addEventListener('submit', async function(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
|
||||||
|
// Show loading, hide results
|
||||||
|
loading.style.display = 'block';
|
||||||
|
results.style.display = 'none';
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await fetch('{{ route("proxy-checker.check") }}', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
'X-CSRF-TOKEN': '{{ csrf_token() }}'
|
||||||
|
},
|
||||||
|
body: JSON.stringify({
|
||||||
|
ip: form.ip.value,
|
||||||
|
port: form.port.value,
|
||||||
|
type: form.type.value,
|
||||||
|
test_url: form.test_url.value
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
const data = await response.json();
|
||||||
|
|
||||||
|
// Hide loading
|
||||||
|
loading.style.display = 'none';
|
||||||
|
|
||||||
|
// Show results
|
||||||
|
results.style.display = 'block';
|
||||||
|
|
||||||
|
if (data.success) {
|
||||||
|
resultContent.innerHTML = `
|
||||||
|
<div class="alert alert-success">
|
||||||
|
<i class="bi bi-check-circle-fill me-2"></i>${data.message}
|
||||||
|
</div>
|
||||||
|
<div class="table-responsive">
|
||||||
|
<table class="table table-sm">
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<th>Status Code:</th>
|
||||||
|
<td>${data.data.status_code}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th>Response Time:</th>
|
||||||
|
<td>${data.data.speed} ms</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th>Content Type:</th>
|
||||||
|
<td>${data.data.content_type}</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
} else {
|
||||||
|
resultContent.innerHTML = `
|
||||||
|
<div class="alert alert-danger">
|
||||||
|
<i class="bi bi-x-circle-fill me-2"></i>${data.message}
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
loading.style.display = 'none';
|
||||||
|
results.style.display = 'block';
|
||||||
|
resultContent.innerHTML = `
|
||||||
|
<div class="alert alert-danger">
|
||||||
|
<i class="bi bi-x-circle-fill me-2"></i>An error occurred while checking the proxy.
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
@endpush
|
||||||
|
@endsection
|
||||||
@@ -1,18 +1,92 @@
|
|||||||
<x-app-layout>
|
@extends('layouts.app')
|
||||||
<x-slot name="header">
|
|
||||||
<h2 class="font-semibold text-xl text-gray-800 leading-tight">
|
|
||||||
{{ __('Subscriptions') }}
|
|
||||||
</h2>
|
|
||||||
</x-slot>
|
|
||||||
|
|
||||||
<div class="py-12">
|
@section('content')
|
||||||
<div class="max-w-7xl mx-auto sm:px-6 lg:px-8">
|
<div class="container py-5">
|
||||||
<div class="bg-white overflow-hidden shadow-sm sm:rounded-lg">
|
<div class="row justify-content-center">
|
||||||
<div class="p-6 text-gray-900">
|
<div class="col-lg-10">
|
||||||
<h3 class="text-lg font-medium mb-4">Available Subscriptions</h3>
|
<div class="text-center mb-5">
|
||||||
<p class="text-gray-600">This page will display available subscription plans. Content coming soon.</p>
|
<h1 class="h2 mb-3">Choose Your Subscription Plan</h1>
|
||||||
|
<p class="text-muted">Select the plan that best fits your needs</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
@if(session('success'))
|
||||||
|
<div class="alert alert-success alert-dismissible fade show" role="alert">
|
||||||
|
{{ session('success') }}
|
||||||
|
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
|
||||||
</div>
|
</div>
|
||||||
|
@endif
|
||||||
|
|
||||||
|
@if(session('error'))
|
||||||
|
<div class="alert alert-danger alert-dismissible fade show" role="alert">
|
||||||
|
{{ session('error') }}
|
||||||
|
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
|
||||||
|
</div>
|
||||||
|
@endif
|
||||||
|
|
||||||
|
@if($userSubscription)
|
||||||
|
<div class="card mb-4">
|
||||||
|
<div class="card-body">
|
||||||
|
<div class="d-flex justify-content-between align-items-center">
|
||||||
|
<div>
|
||||||
|
<h5 class="card-title mb-1">Current Subscription: {{ $userSubscription->subscription->name }}</h5>
|
||||||
|
<p class="card-text text-muted mb-0">
|
||||||
|
Expires: {{ $userSubscription->expires_at->format('F j, Y') }}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<form action="{{ route('subscriptions.cancel', $userSubscription) }}" method="POST" class="d-inline">
|
||||||
|
@csrf
|
||||||
|
@method('DELETE')
|
||||||
|
<button type="submit" class="btn btn-outline-danger" onclick="return confirm('Are you sure you want to cancel your subscription?')">
|
||||||
|
Cancel Subscription
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
@endif
|
||||||
|
|
||||||
|
<div class="row g-4">
|
||||||
|
@foreach($subscriptions as $subscription)
|
||||||
|
<div class="col-md-4">
|
||||||
|
<div class="card h-100 {{ $subscription->name === 'Pro' ? 'border-primary' : '' }}">
|
||||||
|
@if($subscription->name === 'Pro')
|
||||||
|
<div class="card-header bg-primary text-white text-center">
|
||||||
|
<span class="badge bg-white text-primary">Most Popular</span>
|
||||||
|
</div>
|
||||||
|
@endif
|
||||||
|
<div class="card-body">
|
||||||
|
<h3 class="card-title text-center mb-4">{{ $subscription->name }}</h3>
|
||||||
|
<div class="text-center mb-4">
|
||||||
|
<span class="display-4">${{ number_format($subscription->price, 2) }}</span>
|
||||||
|
<span class="text-muted">/month</span>
|
||||||
|
</div>
|
||||||
|
<p class="card-text text-center mb-4">{{ $subscription->description }}</p>
|
||||||
|
<ul class="list-unstyled mb-4">
|
||||||
|
@foreach($subscription->features as $feature)
|
||||||
|
<li class="mb-2">
|
||||||
|
<i class="bi bi-check-circle-fill text-success me-2"></i>
|
||||||
|
{{ $feature }}
|
||||||
|
</li>
|
||||||
|
@endforeach
|
||||||
|
</ul>
|
||||||
|
<div class="text-center">
|
||||||
|
@if($userSubscription && $userSubscription->subscription_id === $subscription->id)
|
||||||
|
<button class="btn btn-outline-primary" disabled>Current Plan</button>
|
||||||
|
@else
|
||||||
|
<form action="{{ route('subscriptions.subscribe', $subscription) }}" method="POST">
|
||||||
|
@csrf
|
||||||
|
<button type="submit" class="btn btn-primary">
|
||||||
|
Subscribe Now
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
|
@endif
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
@endforeach
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</x-app-layout>
|
</div>
|
||||||
|
@endsection
|
||||||
@@ -1,53 +0,0 @@
|
|||||||
@if ($paginator->hasPages())
|
|
||||||
<nav aria-label="Page navigation">
|
|
||||||
<ul class="pagination pagination-sm mb-0">
|
|
||||||
{{-- Previous Page Link --}}
|
|
||||||
@if ($paginator->onFirstPage())
|
|
||||||
<li class="page-item disabled">
|
|
||||||
<span class="page-link">
|
|
||||||
<i class="bi bi-chevron-left"></i>
|
|
||||||
</span>
|
|
||||||
</li>
|
|
||||||
@else
|
|
||||||
<li class="page-item">
|
|
||||||
<a class="page-link" href="{{ $paginator->previousPageUrl() }}" rel="prev">
|
|
||||||
<i class="bi bi-chevron-left"></i>
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
@endif
|
|
||||||
|
|
||||||
{{-- Pagination Elements --}}
|
|
||||||
@foreach ($elements as $element)
|
|
||||||
{{-- Array Of Links --}}
|
|
||||||
@if (is_array($element))
|
|
||||||
@foreach ($element as $page => $url)
|
|
||||||
@if ($page == $paginator->currentPage())
|
|
||||||
<li class="page-item active">
|
|
||||||
<span class="page-link">{{ $page }}</span>
|
|
||||||
</li>
|
|
||||||
@else
|
|
||||||
<li class="page-item">
|
|
||||||
<a class="page-link" href="{{ $url }}">{{ $page }}</a>
|
|
||||||
</li>
|
|
||||||
@endif
|
|
||||||
@endforeach
|
|
||||||
@endif
|
|
||||||
@endforeach
|
|
||||||
|
|
||||||
{{-- Next Page Link --}}
|
|
||||||
@if ($paginator->hasMorePages())
|
|
||||||
<li class="page-item">
|
|
||||||
<a class="page-link" href="{{ $paginator->nextPageUrl() }}" rel="next">
|
|
||||||
<i class="bi bi-chevron-right"></i>
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
@else
|
|
||||||
<li class="page-item disabled">
|
|
||||||
<span class="page-link">
|
|
||||||
<i class="bi bi-chevron-right"></i>
|
|
||||||
</span>
|
|
||||||
</li>
|
|
||||||
@endif
|
|
||||||
</ul>
|
|
||||||
</nav>
|
|
||||||
@endif
|
|
||||||
+23
-1
@@ -5,6 +5,9 @@ use App\Http\Controllers\ProxyController;
|
|||||||
use App\Http\Controllers\ProxyListController;
|
use App\Http\Controllers\ProxyListController;
|
||||||
use App\Http\Controllers\SubscriptionController;
|
use App\Http\Controllers\SubscriptionController;
|
||||||
use App\Http\Controllers\PortScannerController;
|
use App\Http\Controllers\PortScannerController;
|
||||||
|
use App\Http\Controllers\PacFileController;
|
||||||
|
use App\Http\Controllers\ProxyCheckerController;
|
||||||
|
use App\Http\Controllers\IPGeolocationController;
|
||||||
use Illuminate\Support\Facades\Route;
|
use Illuminate\Support\Facades\Route;
|
||||||
|
|
||||||
Route::get('/', function () {
|
Route::get('/', function () {
|
||||||
@@ -33,9 +36,28 @@ Route::get('/proxy-test', function () {
|
|||||||
Route::get('/proxies', [ProxyListController::class, 'index'])->name('proxies.index');
|
Route::get('/proxies', [ProxyListController::class, 'index'])->name('proxies.index');
|
||||||
|
|
||||||
// Subscription routes
|
// Subscription routes
|
||||||
Route::get('/subscriptions', [SubscriptionController::class, 'index'])->name('subscriptions.index');
|
Route::middleware(['auth'])->group(function () {
|
||||||
|
Route::get('/subscriptions', [SubscriptionController::class, 'index'])->name('subscriptions.index');
|
||||||
|
Route::post('/subscriptions/{subscription}/subscribe', [SubscriptionController::class, 'subscribe'])->name('subscriptions.subscribe');
|
||||||
|
Route::delete('/subscriptions/{userSubscription}/cancel', [SubscriptionController::class, 'cancel'])->name('subscriptions.cancel');
|
||||||
|
});
|
||||||
|
|
||||||
Route::get('/port-scanner', [PortScannerController::class, 'index'])->name('port-scanner.index');
|
Route::get('/port-scanner', [PortScannerController::class, 'index'])->name('port-scanner.index');
|
||||||
Route::post('/port-scanner/scan', [PortScannerController::class, 'scan'])->name('port-scanner.scan');
|
Route::post('/port-scanner/scan', [PortScannerController::class, 'scan'])->name('port-scanner.scan');
|
||||||
|
|
||||||
|
// PAC File routes
|
||||||
|
Route::get('/pac-file', function () {
|
||||||
|
return view('pac-file');
|
||||||
|
})->name('pac.file');
|
||||||
|
|
||||||
|
Route::get('/pac-file/generate', [PacFileController::class, 'generate'])->name('pac.generate');
|
||||||
|
|
||||||
|
// Proxy Checker routes
|
||||||
|
Route::get('/proxy-checker', [ProxyCheckerController::class, 'index'])->name('proxy-checker.index');
|
||||||
|
Route::post('/proxy-checker/check', [ProxyCheckerController::class, 'check'])->name('proxy-checker.check');
|
||||||
|
|
||||||
|
// IP Geolocation routes
|
||||||
|
Route::get('/ip-lookup', [IPGeolocationController::class, 'index'])->name('ip-geolocation.index');
|
||||||
|
Route::post('/ip-lookup', [IPGeolocationController::class, 'lookup'])->name('ip-geolocation.lookup');
|
||||||
|
|
||||||
require __DIR__.'/auth.php';
|
require __DIR__.'/auth.php';
|
||||||
|
|||||||
Reference in New Issue
Block a user