Add role history to admin area

This commit is contained in:
DariusIII
2025-12-01 17:15:03 +01:00
parent f543e41dc2
commit 00966f8bd8
7 changed files with 512 additions and 3 deletions
@@ -0,0 +1,108 @@
<?php
namespace App\Http\Controllers\Admin;
use App\Http\Controllers\BasePageController;
use App\Models\User;
use App\Models\UserRoleHistory;
use Illuminate\Http\Request;
use Spatie\Permission\Models\Role;
class AdminUserRoleHistoryController extends BasePageController
{
/**
* Display user role history list
*/
public function index(Request $request)
{
$this->setAdminPrefs();
$meta_title = $title = 'User Role History';
// Get all roles for filter
$roles = Role::all()->pluck('name', 'id')->toArray();
// Build query
$query = UserRoleHistory::with(['user', 'oldRole', 'newRole', 'changedByUser'])
->orderBy('created_at', 'desc');
// Apply filters
if ($request->has('user_id') && !empty($request->input('user_id'))) {
$query->where('user_id', $request->input('user_id'));
}
if ($request->has('username') && !empty($request->input('username'))) {
$query->whereHas('user', function ($q) use ($request) {
$q->where('username', 'like', '%' . $request->input('username') . '%');
});
}
if ($request->has('role_id') && !empty($request->input('role_id'))) {
$query->where(function ($q) use ($request) {
$q->where('old_role_id', $request->input('role_id'))
->orWhere('new_role_id', $request->input('role_id'));
});
}
if ($request->has('change_reason') && !empty($request->input('change_reason'))) {
$query->where('change_reason', 'like', '%' . $request->input('change_reason') . '%');
}
if ($request->has('date_from') && !empty($request->input('date_from'))) {
$query->where('created_at', '>=', $request->input('date_from') . ' 00:00:00');
}
if ($request->has('date_to') && !empty($request->input('date_to'))) {
$query->where('created_at', '<=', $request->input('date_to') . ' 23:59:59');
}
// Pagination
$page = $request->has('page') && is_numeric($request->input('page')) ? $request->input('page') : 1;
$perPage = config('nntmux.items_per_page', 50);
$results = $query->paginate($perPage, ['*'], 'page', $page);
$this->viewData = array_merge($this->viewData, [
'title' => $title,
'meta_title' => $meta_title,
'history' => $results,
'roles' => $roles,
'filters' => [
'user_id' => $request->input('user_id', ''),
'username' => $request->input('username', ''),
'role_id' => $request->input('role_id', ''),
'change_reason' => $request->input('change_reason', ''),
'date_from' => $request->input('date_from', ''),
'date_to' => $request->input('date_to', ''),
],
]);
return view('admin.user-role-history.index', $this->viewData);
}
/**
* Display role history for a specific user
*/
public function show(Request $request, int $userId)
{
$this->setAdminPrefs();
$user = User::findOrFail($userId);
$meta_title = $title = 'Role History for ' . $user->username;
$history = UserRoleHistory::with(['oldRole', 'newRole', 'changedByUser'])
->where('user_id', $userId)
->orderBy('created_at', 'desc')
->paginate(config('nntmux.items_per_page', 50));
$this->viewData = array_merge($this->viewData, [
'title' => $title,
'meta_title' => $meta_title,
'user' => $user,
'history' => $history,
]);
return view('admin.user-role-history.show', $this->viewData);
}
}
@@ -0,0 +1,212 @@
@extends('layouts.admin')
@section('content')
<div class="container mx-auto px-4 py-6">
<div class="bg-white dark:bg-gray-800 rounded-lg shadow-sm border border-gray-200 dark:border-gray-700">
<!-- Header -->
<div class="px-6 py-4 border-b border-gray-200 dark:border-gray-700">
<div class="flex justify-between items-center">
<h1 class="text-2xl font-semibold text-gray-800 dark:text-gray-200">
<i class="fa fa-history mr-2"></i>{{ $title }}
</h1>
</div>
</div>
<!-- Search Filters -->
<div class="px-6 py-4 bg-gray-50 dark:bg-gray-900 border-b border-gray-200 dark:border-gray-700">
<form method="get" action="{{ url('admin/user-role-history') }}">
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
<div>
<label for="username" class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">Username</label>
<input type="text"
id="username"
name="username"
value="{{ $filters['username'] }}"
placeholder="Filter by username"
class="w-full px-3 py-2 bg-white dark:bg-gray-800 text-gray-900 dark:text-gray-100 border border-gray-300 dark:border-gray-600 rounded-md focus:ring-blue-500 dark:focus:ring-blue-400 focus:border-blue-500 dark:focus:border-blue-400">
</div>
<div>
<label for="role_id" class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">Role</label>
<select id="role_id"
name="role_id"
class="w-full px-3 py-2 bg-white dark:bg-gray-800 text-gray-900 dark:text-gray-100 border border-gray-300 dark:border-gray-600 rounded-md focus:ring-blue-500 dark:focus:ring-blue-400 focus:border-blue-500 dark:focus:border-blue-400">
<option value="">All Roles</option>
@foreach($roles as $roleId => $roleName)
<option value="{{ $roleId }}" {{ $filters['role_id'] == $roleId ? 'selected' : '' }}>
{{ $roleName }}
</option>
@endforeach
</select>
</div>
<div>
<label for="change_reason" class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">Change Reason</label>
<input type="text"
id="change_reason"
name="change_reason"
value="{{ $filters['change_reason'] }}"
placeholder="Filter by reason"
class="w-full px-3 py-2 bg-white dark:bg-gray-800 text-gray-900 dark:text-gray-100 border border-gray-300 dark:border-gray-600 rounded-md focus:ring-blue-500 dark:focus:ring-blue-400 focus:border-blue-500 dark:focus:border-blue-400">
</div>
<div>
<label for="date_from" class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">Date From</label>
<input type="date"
id="date_from"
name="date_from"
value="{{ $filters['date_from'] }}"
class="w-full px-3 py-2 bg-white dark:bg-gray-800 text-gray-900 dark:text-gray-100 border border-gray-300 dark:border-gray-600 rounded-md focus:ring-blue-500 dark:focus:ring-blue-400 focus:border-blue-500 dark:focus:border-blue-400">
</div>
<div>
<label for="date_to" class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">Date To</label>
<input type="date"
id="date_to"
name="date_to"
value="{{ $filters['date_to'] }}"
class="w-full px-3 py-2 bg-white dark:bg-gray-800 text-gray-900 dark:text-gray-100 border border-gray-300 dark:border-gray-600 rounded-md focus:ring-blue-500 dark:focus:ring-blue-400 focus:border-blue-500 dark:focus:border-blue-400">
</div>
<div class="flex items-end">
<button type="submit" class="w-full px-4 py-2 bg-blue-600 dark:bg-blue-700 text-white rounded-md hover:bg-blue-700 dark:hover:bg-blue-800">
<i class="fa fa-search mr-2"></i>Filter
</button>
</div>
</div>
<div class="mt-4">
<a href="{{ url('admin/user-role-history') }}" class="text-sm text-blue-600 dark:text-blue-400 hover:underline">
Clear Filters
</a>
</div>
</form>
</div>
<!-- History Table -->
<div class="overflow-x-auto">
<table class="min-w-full divide-y divide-gray-200 dark:divide-gray-700">
<thead class="bg-gray-50 dark:bg-gray-900">
<tr>
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider">
Date
</th>
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider">
User
</th>
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider">
Old Role
</th>
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider">
New Role
</th>
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider">
Old Expiry
</th>
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider">
New Expiry
</th>
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider">
Stacked
</th>
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider">
Reason
</th>
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider">
Changed By
</th>
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider">
Actions
</th>
</tr>
</thead>
<tbody class="bg-white dark:bg-gray-800 divide-y divide-gray-200 dark:divide-gray-700">
@forelse($history as $record)
<tr class="hover:bg-gray-50 dark:hover:bg-gray-700">
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-900 dark:text-gray-100">
{{ $record->created_at->format('Y-m-d H:i:s') }}
</td>
<td class="px-6 py-4 whitespace-nowrap text-sm">
@if($record->user)
<a href="{{ url('admin/user-role-history/' . $record->user_id) }}" class="text-blue-600 dark:text-blue-400 hover:underline">
{{ $record->user->username }}
</a>
@else
<span class="text-gray-500 dark:text-gray-400">User #{{ $record->user_id }}</span>
@endif
</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-900 dark:text-gray-100">
@if($record->oldRole)
<span class="px-2 py-1 text-xs font-medium rounded bg-gray-200 dark:bg-gray-700 text-gray-800 dark:text-gray-200">
{{ $record->oldRole->name }}
</span>
@else
<span class="text-gray-400 dark:text-gray-500">-</span>
@endif
</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-900 dark:text-gray-100">
@if($record->newRole)
<span class="px-2 py-1 text-xs font-medium rounded bg-blue-200 dark:bg-blue-900 text-blue-800 dark:text-blue-200">
{{ $record->newRole->name }}
</span>
@else
<span class="text-gray-400 dark:text-gray-500">-</span>
@endif
</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-600 dark:text-gray-400">
{{ $record->old_expiry_date ? $record->old_expiry_date->format('Y-m-d H:i') : '-' }}
</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-600 dark:text-gray-400">
{{ $record->new_expiry_date ? $record->new_expiry_date->format('Y-m-d H:i') : '-' }}
</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-center">
@if($record->is_stacked)
<span class="px-2 py-1 text-xs font-medium rounded bg-green-200 dark:bg-green-900 text-green-800 dark:text-green-200">
Yes
</span>
@else
<span class="text-gray-400 dark:text-gray-500">No</span>
@endif
</td>
<td class="px-6 py-4 text-sm text-gray-600 dark:text-gray-400">
{{ $record->change_reason ?? '-' }}
</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-600 dark:text-gray-400">
@if($record->changedByUser)
{{ $record->changedByUser->username }}
@else
<span class="text-gray-400 dark:text-gray-500">System</span>
@endif
</td>
<td class="px-6 py-4 whitespace-nowrap text-sm font-medium">
<div class="flex gap-2">
@if($record->user)
<a href="{{ url('admin/user-edit?id=' . $record->user_id) }}"
class="text-blue-600 dark:text-blue-400 hover:text-blue-900 dark:hover:text-blue-300"
title="Edit User">
<i class="fa fa-edit"></i>
</a>
<a href="{{ url('admin/user-role-history/' . $record->user_id) }}"
class="text-purple-600 dark:text-purple-400 hover:text-purple-900 dark:hover:text-purple-300"
title="View User's History">
<i class="fa fa-history"></i>
</a>
@endif
</div>
</td>
</tr>
@empty
<tr>
<td colspan="10" class="px-6 py-8 text-center text-gray-500 dark:text-gray-400">
<i class="fa fa-info-circle mr-2"></i>No role history records found
</td>
</tr>
@endforelse
</tbody>
</table>
</div>
<!-- Pagination -->
@if($history->hasPages())
<div class="px-6 py-4 border-t border-gray-200 dark:border-gray-700">
{{ $history->links() }}
</div>
@endif
</div>
</div>
@endsection
@@ -0,0 +1,173 @@
@extends('layouts.admin')
@section('content')
<div class="container mx-auto px-4 py-6">
<div class="bg-white dark:bg-gray-800 rounded-lg shadow-sm border border-gray-200 dark:border-gray-700">
<!-- Header -->
<div class="px-6 py-4 border-b border-gray-200 dark:border-gray-700">
<div class="flex justify-between items-center">
<h1 class="text-2xl font-semibold text-gray-800 dark:text-gray-200">
<i class="fa fa-history mr-2"></i>{{ $title }}
</h1>
<div class="flex gap-2">
<a href="{{ url('admin/user-edit?id=' . $user->id) }}" class="px-4 py-2 bg-blue-600 dark:bg-blue-700 text-white rounded-lg hover:bg-blue-700 dark:hover:bg-blue-800">
<i class="fa fa-edit mr-2"></i>Edit User
</a>
<a href="{{ url('admin/user-role-history') }}" class="px-4 py-2 bg-gray-600 dark:bg-gray-700 text-white rounded-lg hover:bg-gray-700 dark:hover:bg-gray-800">
<i class="fa fa-arrow-left mr-2"></i>Back to All
</a>
</div>
</div>
</div>
<!-- User Info -->
<div class="px-6 py-4 bg-gray-50 dark:bg-gray-900 border-b border-gray-200 dark:border-gray-700">
<div class="grid grid-cols-1 md:grid-cols-3 gap-4">
<div>
<label class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">Username</label>
<div class="text-lg font-semibold text-gray-900 dark:text-gray-100">{{ $user->username }}</div>
</div>
<div>
<label class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">Email</label>
<div class="text-lg text-gray-900 dark:text-gray-100">{{ $user->email }}</div>
</div>
<div>
<label class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">Current Role</label>
<div class="text-lg text-gray-900 dark:text-gray-100">
@if($user->role)
<span class="px-3 py-1 text-sm font-medium rounded bg-blue-200 dark:bg-blue-900 text-blue-800 dark:text-blue-200">
{{ $user->role->name }}
</span>
@else
<span class="text-gray-500">No role assigned</span>
@endif
</div>
</div>
</div>
@if($user->rolechangedate)
<div class="mt-4">
<label class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">Current Role Expiry</label>
<div class="text-lg text-gray-900 dark:text-gray-100">
{{ \Carbon\Carbon::parse($user->rolechangedate)->format('Y-m-d H:i:s') }}
@if(\Carbon\Carbon::parse($user->rolechangedate)->isPast())
<span class="ml-2 px-2 py-1 text-xs font-medium rounded bg-red-200 dark:bg-red-900 text-red-800 dark:text-red-200">
Expired
</span>
@else
<span class="ml-2 px-2 py-1 text-xs font-medium rounded bg-green-200 dark:bg-green-900 text-green-800 dark:text-green-200">
Active
</span>
@endif
</div>
</div>
@endif
</div>
<!-- History Table -->
<div class="overflow-x-auto">
<table class="min-w-full divide-y divide-gray-200 dark:divide-gray-700">
<thead class="bg-gray-50 dark:bg-gray-900">
<tr>
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider">
Date
</th>
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider">
Old Role
</th>
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider">
New Role
</th>
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider">
Old Expiry
</th>
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider">
New Expiry
</th>
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider">
Effective Date
</th>
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider">
Stacked
</th>
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider">
Reason
</th>
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider">
Changed By
</th>
</tr>
</thead>
<tbody class="bg-white dark:bg-gray-800 divide-y divide-gray-200 dark:divide-gray-700">
@forelse($history as $record)
<tr class="hover:bg-gray-50 dark:hover:bg-gray-700">
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-900 dark:text-gray-100">
{{ $record->created_at->format('Y-m-d H:i:s') }}
</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-900 dark:text-gray-100">
@if($record->oldRole)
<span class="px-2 py-1 text-xs font-medium rounded bg-gray-200 dark:bg-gray-700 text-gray-800 dark:text-gray-200">
{{ $record->oldRole->name }}
</span>
@else
<span class="text-gray-400 dark:text-gray-500">-</span>
@endif
</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-900 dark:text-gray-100">
@if($record->newRole)
<span class="px-2 py-1 text-xs font-medium rounded bg-blue-200 dark:bg-blue-900 text-blue-800 dark:text-blue-200">
{{ $record->newRole->name }}
</span>
@else
<span class="text-gray-400 dark:text-gray-500">-</span>
@endif
</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-600 dark:text-gray-400">
{{ $record->old_expiry_date ? $record->old_expiry_date->format('Y-m-d H:i') : '-' }}
</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-600 dark:text-gray-400">
{{ $record->new_expiry_date ? $record->new_expiry_date->format('Y-m-d H:i') : '-' }}
</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-600 dark:text-gray-400">
{{ $record->effective_date ? $record->effective_date->format('Y-m-d H:i') : '-' }}
</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-center">
@if($record->is_stacked)
<span class="px-2 py-1 text-xs font-medium rounded bg-green-200 dark:bg-green-900 text-green-800 dark:text-green-200">
Yes
</span>
@else
<span class="text-gray-400 dark:text-gray-500">No</span>
@endif
</td>
<td class="px-6 py-4 text-sm text-gray-600 dark:text-gray-400">
{{ $record->change_reason ?? '-' }}
</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-600 dark:text-gray-400">
@if($record->changedByUser)
{{ $record->changedByUser->username }}
@else
<span class="text-gray-400 dark:text-gray-500">System</span>
@endif
</td>
</tr>
@empty
<tr>
<td colspan="9" class="px-6 py-8 text-center text-gray-500 dark:text-gray-400">
<i class="fa fa-info-circle mr-2"></i>No role history records found for this user
</td>
</tr>
@endforelse
</tbody>
</table>
</div>
<!-- Pagination -->
@if($history->hasPages())
<div class="px-6 py-4 border-t border-gray-200 dark:border-gray-700">
{{ $history->links() }}
</div>
@endif
</div>
</div>
@endsection
+10 -3
View File
@@ -5,9 +5,16 @@
<div class="bg-white dark:bg-gray-800 rounded-lg shadow-sm">
<!-- Header -->
<div class="px-6 py-4 border-b border-gray-200 dark:border-gray-700">
<h1 class="text-2xl font-semibold text-gray-800 dark:text-gray-200">
<i class="fa fa-user mr-2"></i>{{ $title }}
</h1>
<div class="flex justify-between items-center">
<h1 class="text-2xl font-semibold text-gray-800 dark:text-gray-200">
<i class="fa fa-user mr-2"></i>{{ $title }}
</h1>
@if(!empty($user['id']))
<a href="{{ url('admin/user-role-history/' . $user['id']) }}" class="px-4 py-2 bg-purple-600 dark:bg-purple-700 text-white rounded-lg hover:bg-purple-700 dark:hover:bg-purple-800">
<i class="fa fa-history mr-2"></i>View Role History
</a>
@endif
</div>
</div>
<!-- Error Messages -->
@@ -315,6 +315,11 @@
title="Edit">
<i class="fa fa-edit"></i>
</a>
<a href="{{ url('admin/user-role-history/' . $user->id) }}"
class="text-purple-600 dark:text-purple-400 hover:text-purple-900 dark:hover:text-purple-300"
title="Role History">
<i class="fa fa-history"></i>
</a>
@if(!$user->verified)
<form method="POST" action="{{ route('admin.verify') }}" class="inline verify-user-form">
@csrf
@@ -19,6 +19,7 @@
<div id="users-menu" class="hidden mt-2 ml-6 space-y-1">
<a href="{{ url('/admin/user-list') }}" class="block py-2 px-3 text-gray-400 dark:text-gray-500 hover:text-white dark:hover:text-white hover:bg-gray-800 dark:hover:bg-gray-800 rounded transition">User List</a>
<a href="{{ url('/admin/role-list') }}" class="block py-2 px-3 text-gray-400 dark:text-gray-500 hover:text-white dark:hover:text-white hover:bg-gray-800 dark:hover:bg-gray-800 rounded transition">Roles</a>
<a href="{{ url('/admin/user-role-history') }}" class="block py-2 px-3 text-gray-400 dark:text-gray-500 hover:text-white dark:hover:text-white hover:bg-gray-800 dark:hover:bg-gray-800 rounded transition">Role History</a>
<a href="{{ url('/admin/promotions') }}" class="block py-2 px-3 text-gray-400 dark:text-gray-500 hover:text-white dark:hover:text-white hover:bg-gray-800 dark:hover:bg-gray-800 rounded transition">Promotions</a>
<a href="{{ url('/admin/deleted-users') }}" class="block py-2 px-3 text-gray-400 dark:text-gray-500 hover:text-white dark:hover:text-white hover:bg-gray-800 dark:hover:bg-gray-800 rounded transition">Deleted Users</a>
</div>
+3
View File
@@ -36,6 +36,7 @@ use App\Http\Controllers\Admin\AdminShowsController;
use App\Http\Controllers\Admin\AdminSiteController;
use App\Http\Controllers\Admin\AdminTmuxController;
use App\Http\Controllers\Admin\AdminUserController;
use App\Http\Controllers\Admin\AdminUserRoleHistoryController;
use App\Http\Controllers\Admin\DeletedUsersController;
use App\Http\Controllers\AdultController;
use App\Http\Controllers\AjaxController;
@@ -194,6 +195,8 @@ Route::middleware('role:Admin', '2fa')->prefix('admin')->group(function () {
Route::post('user-delete', [AdminUserController::class, 'destroy'])->name('admin.user-delete');
Route::post('verify', [AdminUserController::class, 'verify'])->name('admin.verify');
Route::post('resendverification', [AdminUserController::class, 'resendVerification'])->name('admin.resend-verification');
Route::get('user-role-history', [AdminUserRoleHistoryController::class, 'index'])->name('admin.user-role-history');
Route::get('user-role-history/{userId}', [AdminUserRoleHistoryController::class, 'show'])->name('admin.user-role-history.show');
Route::match(['GET', 'POST'], 'site-edit', [AdminSiteController::class, 'edit'])->name('admin.site-edit');
Route::get('site-stats', [AdminSiteController::class, 'stats'])->name('admin.site-stats');
Route::get('role-list', [AdminRoleController::class, 'index'])->name('admin.role-list');