lots of progress

This commit is contained in:
2025-03-31 23:49:32 +03:00
parent 5b26f832cd
commit 213f0ea8f1
17 changed files with 1067 additions and 68 deletions
@@ -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.');
} }
} }
+36
View File
@@ -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);
}
}
+13
View File
@@ -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();
}
} }
+40
View File
@@ -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');
}
};
+67
View File
@@ -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') }}
+151
View File
@@ -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
+87 -13
View File
@@ -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>
@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>
</div> </div>
</div> </div>
</x-app-layout> @endforeach
</div>
</div>
</div>
</div>
@endsection
-53
View File
@@ -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
View File
@@ -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';