81 lines
4.4 KiB
PHP
81 lines
4.4 KiB
PHP
<?php
|
|
|
|
use App\Http\Controllers\ImpersonationController;
|
|
use App\Http\Controllers\StripeWebhookController;
|
|
use App\Livewire\Admin;
|
|
use App\Livewire\Billing;
|
|
use App\Livewire\Auth\Login;
|
|
use App\Livewire\Auth\TwoFactorChallenge;
|
|
use App\Livewire\Backups;
|
|
use App\Livewire\Cloud;
|
|
use App\Livewire\Dashboard;
|
|
use App\Livewire\Invoices;
|
|
use App\Livewire\Support;
|
|
use App\Livewire\Users;
|
|
use Illuminate\Support\Facades\Route;
|
|
|
|
Route::get('/', fn () => view('landing'))->name('home');
|
|
|
|
// Stripe webhook — paid order → customer provisioning run (CSRF-exempt, signed).
|
|
Route::post('/webhooks/stripe', StripeWebhookController::class)->name('webhooks.stripe');
|
|
|
|
// Public legal pages (placeholders — replace with real content before launch).
|
|
Route::prefix('legal')->name('legal.')->group(function () {
|
|
Route::get('/impressum', fn () => view('legal', ['title' => 'Impressum']))->name('impressum');
|
|
Route::get('/datenschutz', fn () => view('legal', ['title' => 'Datenschutz']))->name('datenschutz');
|
|
Route::get('/agb', fn () => view('legal', ['title' => 'AGB']))->name('agb');
|
|
Route::get('/status', fn () => view('legal', ['title' => 'Status']))->name('status');
|
|
});
|
|
|
|
// Guest auth pages — full-page class-based Livewire components (R1/R2). Fortify
|
|
// handles the POST actions (login.store, two-factor.login.store) with views off.
|
|
Route::middleware('guest')->group(function () {
|
|
Route::get('/login', Login::class)->name('login');
|
|
Route::get('/register', \App\Livewire\Auth\Register::class)->name('register');
|
|
// Registration POST goes through Fortify's controller but with our own
|
|
// registration-scoped throttle (Fortify's built-in route has no limiter).
|
|
Route::post('/register', [\Laravel\Fortify\Http\Controllers\RegisteredUserController::class, 'store'])
|
|
->middleware('throttle:registration')
|
|
->name('register.store');
|
|
Route::get('/two-factor-challenge', TwoFactorChallenge::class)->name('two-factor.login');
|
|
});
|
|
|
|
// Customer portal — each sidebar tab is a full-page class-based Livewire
|
|
// component (R1/R2); paths are English (R13).
|
|
Route::middleware(['auth', 'customer.active'])->group(function () {
|
|
Route::get('/dashboard', Dashboard::class)->name('dashboard');
|
|
Route::get('/cloud', Cloud::class)->name('cloud');
|
|
Route::get('/users', Users::class)->name('users');
|
|
Route::get('/backups', Backups::class)->name('backups');
|
|
Route::get('/invoices', Invoices::class)->name('invoices');
|
|
Route::get('/billing', Billing::class)->name('billing');
|
|
Route::get('/settings', \App\Livewire\Settings::class)->name('settings');
|
|
Route::get('/support', Support::class)->name('support');
|
|
|
|
// Return from an admin impersonation session (accessible as the customer user).
|
|
// POST so Laravel's CSRF middleware protects the identity change.
|
|
Route::post('/impersonate/leave', [ImpersonationController::class, 'leave'])->name('impersonate.leave');
|
|
});
|
|
|
|
// Admin / operator console — dark theme, gated to is_admin users (R1/R2, R13).
|
|
// RestrictAdminHost is BOTH prepended to the `web` group (deterministic 404 on
|
|
// direct hits, even for guests) AND listed here so Livewire records it on the
|
|
// component snapshot and re-applies it to /livewire/update requests — otherwise
|
|
// admin actions could be invoked through a public hostname.
|
|
Route::middleware(['admin.host', 'auth', 'admin'])->prefix('admin')->name('admin.')->group(function () {
|
|
Route::get('/', Admin\Overview::class)->name('overview');
|
|
Route::get('/customers', Admin\Customers::class)->name('customers');
|
|
Route::get('/instances', Admin\Instances::class)->name('instances');
|
|
Route::get('/hosts', Admin\Hosts::class)->name('hosts');
|
|
Route::get('/hosts/create', Admin\HostCreate::class)->name('hosts.create');
|
|
Route::get('/hosts/{host}', Admin\HostDetail::class)->name('hosts.show');
|
|
Route::get('/datacenters', Admin\Datacenters::class)->name('datacenters');
|
|
// POST so the identity change is CSRF-protected (a GET could be forced cross-site).
|
|
Route::post('/impersonate/{customer}', [ImpersonationController::class, 'start'])->name('impersonate');
|
|
Route::get('/provisioning', Admin\Provisioning::class)->name('provisioning');
|
|
Route::get('/maintenance', Admin\Maintenance::class)->name('maintenance');
|
|
Route::get('/vpn', Admin\Vpn::class)->name('vpn');
|
|
Route::get('/revenue', Admin\Revenue::class)->name('revenue');
|
|
Route::get('/settings', Admin\Settings::class)->name('settings');
|
|
});
|