Files
newznab-tmux-NNTmux/app/Http/Controllers/Admin/AdminInvitationController.php
T
DariusIII 560bdf7e62 CS fixes
2025-08-11 23:21:20 +02:00

277 lines
8.8 KiB
PHP

<?php
namespace App\Http\Controllers\Admin;
use App\Http\Controllers\BasePageController;
use App\Models\Invitation;
use App\Models\User;
use App\Services\InvitationService;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
class AdminInvitationController extends BasePageController
{
protected InvitationService $invitationService;
public function __construct(InvitationService $invitationService)
{
parent::__construct();
$this->invitationService = $invitationService;
}
/**
* Display all invitations statistics and management page
*/
public function index(Request $request): void
{
$this->setAdminPrefs();
$meta_title = $title = 'Invitation Management';
// Get filter parameters
$status = $request->get('status', '');
$invited_by = $request->get('invited_by', '');
$email = $request->get('email', '');
$orderBy = $request->get('ob', 'created_at_desc');
$page = $request->get('page', 1);
// Build query
$query = Invitation::with(['invitedBy', 'usedBy']);
// Apply filters
if ($status) {
switch ($status) {
case 'pending':
$query->valid(); // Active, not expired, not used
break;
case 'used':
$query->used(); // Has used_at timestamp
break;
case 'expired':
$query->expired(); // expires_at is in the past
break;
case 'cancelled':
$query->where('is_active', false)
->whereNull('used_at'); // Inactive but not used = cancelled
break;
}
}
if ($invited_by) {
$user = User::where('username', 'like', '%'.$invited_by.'%')->first();
if ($user) {
$query->where('invited_by', $user->id);
}
}
if ($email) {
$query->where('email', 'like', '%'.$email.'%');
}
// Apply ordering
switch ($orderBy) {
case 'created_at_asc':
$query->orderBy('created_at', 'asc');
break;
case 'created_at_desc':
$query->orderBy('created_at', 'desc');
break;
case 'expires_at_asc':
$query->orderBy('expires_at', 'asc');
break;
case 'expires_at_desc':
$query->orderBy('expires_at', 'desc');
break;
case 'email_asc':
$query->orderBy('email', 'asc');
break;
case 'email_desc':
$query->orderBy('email', 'desc');
break;
default:
$query->orderBy('created_at', 'desc');
}
// Paginate results
$invitations = $query->paginate(config('nntmux.items_per_page', 25));
// Get overall statistics
$stats = $this->getOverallStats();
// Get user statistics (top inviters)
$topInviters = $this->getTopInviters();
$this->smarty->assign([
'invitations' => $invitations,
'stats' => $stats,
'topInviters' => $topInviters,
'status' => $status,
'invited_by' => $invited_by,
'email' => $email,
'orderBy' => $orderBy,
'statusOptions' => [
'' => 'All',
'pending' => 'Pending',
'used' => 'Used',
'expired' => 'Expired',
'cancelled' => 'Cancelled',
],
]);
$content = $this->smarty->fetch('admin-invitation-list.tpl');
$this->smarty->assign(compact('title', 'meta_title', 'content'));
$this->adminrender();
}
/**
* Get overall invitation statistics
*/
private function getOverallStats(): array
{
return [
'total' => Invitation::count(),
'pending' => Invitation::valid()->count(),
'used' => Invitation::used()->count(),
'expired' => Invitation::expired()->count(),
'cancelled' => Invitation::where('is_active', false)->whereNull('used_at')->count(),
'today' => Invitation::whereDate('created_at', today())->count(),
'this_week' => Invitation::whereBetween('created_at', [
now()->startOfWeek(),
now()->endOfWeek(),
])->count(),
'this_month' => Invitation::whereMonth('created_at', now()->month)
->whereYear('created_at', now()->year)
->count(),
];
}
/**
* Get top inviters statistics
*/
private function getTopInviters(int $limit = 10): array
{
return User::select('users.*')
->selectRaw('COUNT(invitations.id) as total_invitations')
->selectRaw('COUNT(CASE WHEN invitations.used_at IS NOT NULL THEN 1 END) as successful_invitations')
->leftJoin('invitations', 'users.id', '=', 'invitations.invited_by')
->groupBy('users.id')
->having('total_invitations', '>', 0)
->orderBy('total_invitations', 'desc')
->limit($limit)
->get()
->toArray();
}
/**
* Cancel an invitation
*/
public function cancel(Request $request): RedirectResponse
{
try {
$id = $request->route('id');
$this->invitationService->cancelInvitation($id);
return redirect()->back()->with('success', 'Invitation cancelled successfully');
} catch (\Exception $e) {
return redirect()->back()->with('error', 'Failed to cancel invitation: '.$e->getMessage());
}
}
/**
* Resend an invitation
*/
public function resend(Request $request): RedirectResponse
{
try {
$id = $request->route('id');
$this->invitationService->resendInvitation($id);
return redirect()->back()->with('success', 'Invitation resent successfully');
} catch (\Exception $e) {
return redirect()->back()->with('error', 'Failed to resend invitation: '.$e->getMessage());
}
}
/**
* Cleanup expired invitations
*/
public function cleanup(Request $request): RedirectResponse
{
try {
$cleanedCount = $this->invitationService->cleanupExpiredInvitations();
return redirect()->back()->with('success', "Cleaned up {$cleanedCount} expired invitations");
} catch (\Exception $e) {
return redirect()->back()->with('error', 'Failed to cleanup invitations: '.$e->getMessage());
}
}
/**
* View detailed invitation
*/
public function show(Request $request): void
{
$this->setAdminPrefs();
$id = $request->route('id');
$invitation = Invitation::with(['invitedBy', 'usedBy'])->findOrFail($id);
$meta_title = $title = 'Invitation Details';
$this->smarty->assign([
'invitation' => $invitation,
]);
$content = $this->smarty->fetch('admin-invitation-show.tpl');
$this->smarty->assign(compact('title', 'meta_title', 'content'));
$this->adminrender();
}
/**
* Bulk actions on invitations
*/
public function bulkAction(Request $request): RedirectResponse
{
$action = $request->get('bulk_action');
$invitationIds = $request->get('invitation_ids', []);
if (empty($invitationIds)) {
return redirect()->back()->with('error', 'No invitations selected');
}
try {
$count = 0;
switch ($action) {
case 'cancel':
foreach ($invitationIds as $id) {
$this->invitationService->cancelInvitation($id);
$count++;
}
return redirect()->back()->with('success', "Cancelled {$count} invitations");
case 'resend':
foreach ($invitationIds as $id) {
$this->invitationService->resendInvitation($id);
$count++;
}
return redirect()->back()->with('success', "Resent {$count} invitations");
case 'delete':
Invitation::whereIn('id', $invitationIds)->delete();
$count = count($invitationIds);
return redirect()->back()->with('success', "Deleted {$count} invitations");
default:
return redirect()->back()->with('error', 'Invalid bulk action');
}
} catch (\Exception $e) {
return redirect()->back()->with('error', 'Bulk action failed: '.$e->getMessage());
}
}
}