Files
website/website/app/Http/Controllers/Admin/ImpersonationController.php
Claude Dev 45d25d61ba Idempotent provisioning, service soft-delete, Plans page redesign, doc updates
Part A: Fix duplicate Service creation on provisioning retry
- All 4 provisioning services use Service::firstOrCreate() keyed on
  subscription_id+service_type to prevent duplicates on queue retries
- HandleSubscriptionCreated sends notification before provisioning,
  no longer re-throws on failure
- RetryProvisioningCommand simplified to reuse existing Service records

Part B: Plans/Pricing page complete redesign
- Service type tabs (VPS, Dedicated, Web Hosting, MySQL)
- Billing cycle segmented toggle (monthly/quarterly/semi-annual/annual)
- Feature icons per service type, Popular/Best Value badges
- Stock indicators, effective monthly price calculations

Part C: Admin service soft-delete/archive
- Service model uses SoftDeletes trait
- Admin can archive and restore services
- Show archived toggle on services list
- Migration adds deleted_at column

Docs: Updated TASKS.md, CLAUDE.md, PROJECT_DEVELOPMENT.md, MEMORY.md
- Phase 3 marked complete, test counts updated (252 passing)
- SupportPal references replaced with standalone ticket system
- Frontend design skill background rule added
- Closed GitHub issues #3, #6, #7, #8, #9

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-10 06:30:57 -05:00

69 lines
2.0 KiB
PHP

<?php
declare(strict_types=1);
namespace App\Http\Controllers\Admin;
use App\Http\Controllers\Controller;
use App\Models\AuditLog;
use App\Models\User;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
class ImpersonationController extends Controller
{
public function start(Request $request, User $user): RedirectResponse
{
if ($user->isAdmin()) {
return redirect()
->back()
->with('error', 'Cannot impersonate admin users.');
}
AuditLog::query()->create([
'user_id' => $user->id,
'admin_id' => $request->user()->id,
'action' => 'impersonate_start',
'resource_type' => 'User',
'resource_id' => $user->id,
'ip_address' => $request->ip(),
'user_agent' => $request->userAgent(),
'changes' => [
'admin' => $request->user()->name,
'customer' => $user->name,
],
]);
$request->session()->put('impersonator_id', $request->user()->id);
Auth::login($user);
return redirect()->away('https://'.config('app.domains.account').'/dashboard')
->with('info', "You are now impersonating {$user->name}.")
->with('success', "Impersonation started. You are now viewing as {$user->name}.");
}
public function stop(Request $request): RedirectResponse
{
$impersonatorId = $request->session()->get('impersonator_id');
if (! $impersonatorId) {
return redirect()->back();
}
$admin = User::find($impersonatorId);
if (! $admin) {
return redirect()->back()->with('error', 'Original admin user not found.');
}
$request->session()->forget('impersonator_id');
Auth::login($admin);
return redirect('https://'.config('app.domains.admin').'/dashboard')
->with('success', 'Impersonation ended.');
}
}