From b31dd1b8fb54dbbac11cca825a612eff295cfa77 Mon Sep 17 00:00:00 2001 From: mina-esn Date: Thu, 20 Aug 2026 07:56:06 +0330 Subject: [PATCH] feat: implement admin management --- .../Controllers/Admin/AdminController.php | 79 +++++++- app/Http/Requests/Admin/AdminStoreRequest.php | 32 +++ app/Models/Admin.php | 13 +- app/Models/AdminAvatar.php | 50 +++++ app/Models/File.php | 8 +- app/helpers/helper.php | 33 +++ resources/views/admin/admins/create.blade.php | 101 ++++++---- resources/views/admin/admins/index.blade.php | 4 +- resources/views/admin/admins/trash.blade.php | 185 ++++++++++++++++- .../views/admin/layouts/sidebar.blade.php | 126 +++--------- routes/admin.php | 110 ++++++---- .../62189f3220916d712cf7f502e6685f44.php | 107 ++++++---- .../945546a0bb70eafbd9d633e2e262f122.php | 4 +- .../ee09876db1d012ea2d4abc34d2bf5030.php | 188 ++++++++++++++++++ .../eef00d2e3a9c515499bd90866b295b14.php | 124 +++--------- 15 files changed, 838 insertions(+), 326 deletions(-) create mode 100644 app/Models/AdminAvatar.php create mode 100644 storage/framework/views/ee09876db1d012ea2d4abc34d2bf5030.php diff --git a/app/Http/Controllers/Admin/AdminController.php b/app/Http/Controllers/Admin/AdminController.php index f80a85a..5524e47 100644 --- a/app/Http/Controllers/Admin/AdminController.php +++ b/app/Http/Controllers/Admin/AdminController.php @@ -5,6 +5,7 @@ namespace App\Http\Controllers\Admin; use App\Http\Controllers\Controller; use App\Http\Requests\Admin\AdminStoreRequest; use App\Models\Admin; +use App\Models\AdminAvatar; use App\Models\AdminPermission; use App\Models\File; use Illuminate\Database\Eloquent\Builder; @@ -72,6 +73,8 @@ class AdminController extends Controller ->paginate() ->withQueryString(); + + return view('admin.admins.index', compact('title', 'admins')); } @@ -132,19 +135,20 @@ class AdminController extends Controller 'extension' => $image->extension(), ]); -// AdminAvatar::create([ -// 'admin_id' => $admin->id, -// 'file_id' => $file->id, -// ]); + AdminAvatar::create([ + 'admin_id' => $admin->id, + 'file_id' => $file->id, + ]); } - foreach ($data['permissions'] as $permission) { + foreach ($data['permissions'] ?? [] as $permission) { AdminPermission::create([ 'admin_id' => $admin->id, 'permission' => $permission, ]); } + DB::commit(); return redirect() @@ -177,23 +181,80 @@ class AdminController extends Controller } - public function destroy() + public function destroy(Admin $admin) { + if ($admin->id === auth('admin')->id()) { + return back()->with('error', 'امکان حذف حساب کاربری خودتان وجود ندارد.'); + } + + try { + $admin->delete(); + + return redirect() + ->route('admin.admins.index') + ->with('success', 'مدیر با موفقیت به سطل زباله منتقل شد.'); + + } catch (\Exception $exception) { + Log::error('خطا در حذف مدیر', [ + 'admin_id' => $admin->id, + 'message' => $exception->getMessage(), + ]); + + return back()->with('error', 'خطایی هنگام حذف مدیر رخ داد.'); + } } public function trash() { - + $title = 'مدیران حذف شده'; + $admins = Admin::onlyTrashed() + ->paginate(); + return view('admin.admins.trash' , compact('title' , 'admins')); } - public function restore() + public function restore($id) { + $admin = Admin::onlyTrashed()->findOrFail($id); + $admin->restore(); + + return redirect() + ->route('admin.admins.trash.index') + ->with('success', 'مدیر با موفقیت بازیابی شد.'); } - public function forceDelete() + public function forceDelete($id) { + $admin = Admin::onlyTrashed()->findOrFail($id); + $avatar = $admin->avatar()->with('file')->first(); + $file = $avatar?->file; + + DB::beginTransaction(); + + try { + $avatar?->delete(); + + deleteFile($file); + + $admin->forceDelete(); + + DB::commit(); + + return redirect() + ->route('admin.admins.trash.index') + ->with('success', 'مدیر و آواتار او برای همیشه حذف شدند.'); + + } catch (\Exception $exception) { + DB::rollBack(); + + Log::error('خطا در حذف دائمی مدیر', [ + 'admin_id' => $admin->id, + 'message' => $exception->getMessage(), + ]); + + return back()->with('error', 'حذف دائمی مدیر با خطا مواجه شد.'); + } } } diff --git a/app/Http/Requests/Admin/AdminStoreRequest.php b/app/Http/Requests/Admin/AdminStoreRequest.php index 393bd27..d33e1c0 100644 --- a/app/Http/Requests/Admin/AdminStoreRequest.php +++ b/app/Http/Requests/Admin/AdminStoreRequest.php @@ -88,5 +88,37 @@ class AdminStoreRequest extends FormRequest Rule::enum(AdminPermission::class), ], ]; + + } + public function withValidator($validator): void + { + $validator->after(function ($validator) { + + $role = $this->input('role'); + + $permissions = $this->input('permissions', []); + + + $isSuperAdmin = + $role === \App\Enums\Admin\AdminRole::SUPERADMIN->value; + + + $manageAdminsPermission = + \App\Enums\Admin\AdminPermission::MANAGE_ADMINS->value; + + + if ( + !$isSuperAdmin && + in_array($manageAdminsPermission, $permissions) + ) { + + $validator->errors()->add( + 'permissions', + 'مدیر عادی نمی‌تواند دسترسی مدیریت مدیران را داشته باشد.' + ); + + } + + }); } } diff --git a/app/Models/Admin.php b/app/Models/Admin.php index d417f31..eb2aa94 100644 --- a/app/Models/Admin.php +++ b/app/Models/Admin.php @@ -79,9 +79,18 @@ class Admin extends User { return $this->hasMany(AdminPermission::class); } - public function hasPermission(string $permission): bool + public function avatar() { - if ($this->role === AdminRole::SUPERADMIN) { + return $this->hasOne(AdminAvatar::class); + } + public function isSuperAdmin(): bool + { + return $this->role === \App\Enums\Admin\AdminRole::SUPERADMIN; + } + + public function canAccess(string $permission): bool + { + if ($this->isSuperAdmin()) { return true; } diff --git a/app/Models/AdminAvatar.php b/app/Models/AdminAvatar.php new file mode 100644 index 0000000..7196961 --- /dev/null +++ b/app/Models/AdminAvatar.php @@ -0,0 +1,50 @@ + 'int', + 'admin_id' => 'int' + ]; + + protected $fillable = [ + 'file_id', + 'admin_id' + ]; + + public function admin() + { + return $this->belongsTo(Admin::class); + } + + public function file() + { + return $this->belongsTo(File::class); + } +} diff --git a/app/Models/File.php b/app/Models/File.php index 5f051e0..146e833 100644 --- a/app/Models/File.php +++ b/app/Models/File.php @@ -12,7 +12,7 @@ use Illuminate\Database\Eloquent\Model; /** * Class File - * + * * @property int $id * @property string $name * @property string $extension @@ -21,7 +21,7 @@ use Illuminate\Database\Eloquent\Model; * @property string $path * @property Carbon $created_at * @property Carbon $updated_at - * + * * @property Collection|Flight[] $flights * @property Collection|User[] $users * @@ -53,4 +53,8 @@ class File extends Model { return $this->hasMany(User::class); } + public function adminAvatar() + { + return $this->hasOne(AdminAvatar::class); + } } diff --git a/app/helpers/helper.php b/app/helpers/helper.php index 2616d58..24e7625 100644 --- a/app/helpers/helper.php +++ b/app/helpers/helper.php @@ -83,3 +83,36 @@ if (!function_exists('getUserFullName')) { return $user->first_name . ' ' . $user->last_name; } } +if (! function_exists('deleteFile')) { + function deleteFile(?File $file): void + { + if (! $file) { + return; + } + + + if (Storage::exists($file->path)) { + Storage::delete($file->path); + } + + + $file->delete(); + } +} + +if (!function_exists('getFileUrl')) { + function getFileUrl(?int $fileId): ?string + { + if (!$fileId){ + return null; + } + + $file = File::find($fileId); + + if (!$file){ + return null; + } + return \Illuminate\Support\Facades\Storage::url($file->path); + + } +} diff --git a/resources/views/admin/admins/create.blade.php b/resources/views/admin/admins/create.blade.php index c008428..e496a54 100644 --- a/resources/views/admin/admins/create.blade.php +++ b/resources/views/admin/admins/create.blade.php @@ -206,27 +206,22 @@ @error('role') - {{ $message }} - + {{ $message }} + @enderror @@ -271,7 +266,7 @@ {{-- Permissions --}} -
+
@@ -286,14 +281,18 @@
@foreach(\App\Enums\Admin\AdminPermission::cases() as $permission) +
+
+ - @error('permissions') -
- - {{ $message }} - -
+ + {{ $message }} + @enderror @error('permissions.*') -
- - {{ $message }} - -
+ + {{ $message }} + @enderror
@@ -367,6 +361,7 @@ onchange="previewAvatar(this)" > +
@@ -414,27 +409,61 @@
@endsection - - @push('scripts') - + + roleSelect.addEventListener( + 'change', + handleAdminPermissions + ); + + + handleAdminPermissions(); + + }); + + @endpush diff --git a/resources/views/admin/admins/index.blade.php b/resources/views/admin/admins/index.blade.php index bfbfff5..2a6893d 100644 --- a/resources/views/admin/admins/index.blade.php +++ b/resources/views/admin/admins/index.blade.php @@ -17,7 +17,9 @@ @section('content')
- + @if(session('success')) + {{session('success')}} + @endif
diff --git a/resources/views/admin/admins/trash.blade.php b/resources/views/admin/admins/trash.blade.php index a084222..bde8457 100644 --- a/resources/views/admin/admins/trash.blade.php +++ b/resources/views/admin/admins/trash.blade.php @@ -1,3 +1,182 @@ -
- -
+@extends('admin.layouts.app') + +@section('breadcrumb') +
+
+

مدیران حذف شده

+
+ +
+
+
+@endsection + +@section('content') +
+ +
+
+
+
+
+ +
+
+ مدیران حذف‌شده +
+
+ + + +
+
+
+
+
+ +
+
+
+
+ + + + + + + + + + + + + + + + @if(session('success')) + + + + @endif + + @if($errors->any()) + + + + @endif + + @forelse($admins as $admin) + + + + + + + + + + + + + + + + + + @empty + + + + @endforelse + + +
تصویرنام و نام خانوادگینام کاربریایمیلنوع حسابتاریخ ثبتتاریخ حذفعملیات
+ {{ session('success') }} +
+ @foreach($errors->all() as $error) +
{{ $error }}
+ @endforeach +
+ + {{ $admin->first_name }} {{ $admin->last_name }} + + + {{ $admin->first_name }} {{ $admin->last_name }} + + {{ $admin->username }} + + {{ $admin->email ?: '-' }} + + @if($admin->is_super) + مدیر کل + @else + مدیر عادی + @endif + + {{ $admin->created_at->toJalali()->format('H:i Y/m/d') }} + + {{ $admin->deleted_at?->toJalali()->format('H:i Y/m/d') }} + +
+ +
+ @csrf + + +
+ +
+ @csrf + @method('DELETE') + + +
+ +
+
+ مدیری در سطل زباله وجود ندارد. +
+ + +
+
+
+
+ +
+@endsection diff --git a/resources/views/admin/layouts/sidebar.blade.php b/resources/views/admin/layouts/sidebar.blade.php index 02b6ab2..b4e3f83 100644 --- a/resources/views/admin/layouts/sidebar.blade.php +++ b/resources/views/admin/layouts/sidebar.blade.php @@ -49,19 +49,13 @@ - @if(auth('admin')->user()?->role == \App\Enums\Admin\AdminRole::SUPERADMIN) -
  • - - - - + @if(auth('admin')->user()?->isSuperAdmin()) +
  • + + + + مدیریت مدیران
  • @@ -69,91 +63,37 @@ -
  • - - - - - - - مدیریت کاربران - -
  • + @if(auth('admin')->user()?->canAccess('manage-users')) +
  • + + + مدیریت کاربران + +
  • + @endif
  • - - - - - مدیریت محصولات + + + مدیریت تورها
  • + @if(auth('admin')->user()?->canAccess('manage-flights'))
  • - - - - - - - - - مدیریت دسته‌بندی‌ها - -
  • - - - -
  • - - - - مدیریت پیام ها - -
  • - - - -
  • - - - - مدیریت سوالات متداول - -
  • - - - -
  • - - - - مدیریت اسلایدر + + + مدیریت پروازها
  • + @endif @@ -167,18 +107,6 @@ - -
  • - -{{-- activeAdminSidebar()--}} - - - تنظیمات داده های تصویری - -
  • - -
  • - + خروج از حساب کاربری
  • diff --git a/routes/admin.php b/routes/admin.php index 9c4e8cf..cd9a4a7 100644 --- a/routes/admin.php +++ b/routes/admin.php @@ -3,6 +3,8 @@ use App\Http\Controllers\Admin\AuthController; use App\Http\Controllers\Admin\DashboardController; use App\Http\Controllers\Admin\AdminController; +use App\Http\Controllers\Admin\TourController; +use App\Http\Controllers\Admin\FlightController; use App\Http\Controllers\Admin\UserController; use Illuminate\Support\Facades\Route; @@ -28,62 +30,102 @@ Route::prefix('admin')->name('admin.')->group(function () { Route::prefix('admins')->name('admins.')->middleware('admin.super')->controller(AdminController::class)->group(function () { - Route::get('/', 'index')->name('index'); + Route::get('/', 'index')->name('index'); - Route::get('create', 'create')->name('create'); - Route::post('/', 'store')->name('store'); + Route::get('create', 'create')->name('create'); + Route::post('/', 'store')->name('store'); - Route::prefix('{admin}')->group(function () { - Route::get('edit', 'edit')->name('edit'); - Route::put('/', 'update')->name('update'); - Route::delete('/', 'destroy')->name('destroy'); - }); - - Route::prefix('trash')->name('trash.')->group(function () { - - Route::get('/', 'trash')->name('index'); - - Route::prefix('{id}')->group(function () { - Route::post('restore', 'restore')->name('restore'); - Route::delete('/', 'forceDelete')->name('force-delete'); - }); - }); + Route::prefix('{admin}')->group(function () { + Route::get('edit', 'edit')->name('edit'); + Route::put('/', 'update')->name('update'); + Route::delete('/', 'destroy')->name('destroy'); }); + Route::prefix('trash')->name('trash.')->group(function () { + + Route::get('/', 'trash')->name('index'); + + Route::prefix('{id}')->group(function () { + Route::post('restore', 'restore')->name('restore'); + Route::delete('/', 'forceDelete')->name('force-delete'); + }); + }); + }); + Route::prefix('users')->name('users.')->middleware('admin.permission:manage-users')->controller(UserController::class)->group(function () { - Route::get('/', 'index')->name('index'); + Route::get('/', 'index')->name('index'); - Route::prefix('trash')->group(function () { + Route::prefix('trash')->name('trash.')->group(function () { - Route::get('/', 'trash')->name('trash'); + Route::get('/', 'trash')->name('index'); - Route::prefix('{id}')->group(function () { + Route::prefix('{id}')->group(function () { - Route::post('restore', 'restore')->name('restore'); - Route::delete('force-delete', 'forceDelete')->name('forceDelete'); - }); + Route::post('restore', 'restore')->name('restore'); + Route::delete('force-delete', 'forceDelete')->name('forceDelete'); }); + }); - Route::prefix('{user}')->group(function () { + Route::prefix('{user}')->group(function () { - Route::get('show', 'show')->name('show'); + Route::get('show', 'show')->name('show'); - Route::get('edit', 'edit')->name('edit'); - Route::put('update', 'update')->name('update'); + Route::get('edit', 'edit')->name('edit'); + Route::put('update', 'update')->name('update'); - Route::delete('destroy', 'destroy')->name('destroy'); - - }); + Route::delete('destroy', 'destroy')->name('destroy'); }); + }); + Route::prefix('flights')->name('flights.')->middleware('admin.permission:manage-flights')->controller(FlightController::class)->group(function () { + Route::get('/', 'index')->name('index'); + Route::get('create', 'create')->name('create'); + Route::post('store', 'store')->name('store'); + Route::prefix('trash')->group(function () { + Route::get('/', 'trash')->name('trash'); + + Route::prefix('{id}')->group(function () { + Route::post('restore', 'restore')->name('restore'); + Route::delete('force-delete', 'forceDelete')->name('forceDelete'); + }); + }); + + Route::prefix('{flight}')->group(function () { + Route::get('show', 'show')->name('show'); + Route::get('edit', 'edit')->name('edit'); + Route::put('update', 'update')->name('update'); + Route::delete('destroy', 'destroy')->name('destroy'); + }); + }); + Route::prefix('tours')->name('tours.')->middleware('admin.permission:manage-tours')->controller(TourController::class)->group(function () { + + Route::get('/', 'index')->name('index'); + Route::get('create', 'create')->name('create'); + Route::post('store', 'store')->name('store'); + + Route::prefix('trash')->group(function () { + Route::get('/', 'trash')->name('trash'); + + Route::prefix('{id}')->group(function () { + Route::post('restore', 'restore')->name('restore'); + Route::delete('force-delete', 'forceDelete')->name('forceDelete'); + }); + }); + + Route::prefix('{tour}')->group(function () { + Route::get('show', 'show')->name('show'); + Route::get('edit', 'edit')->name('edit'); + Route::put('update', 'update')->name('update'); + Route::delete('destroy', 'destroy')->name('destroy'); + }); }); + }); -}); - + }); diff --git a/storage/framework/views/62189f3220916d712cf7f502e6685f44.php b/storage/framework/views/62189f3220916d712cf7f502e6685f44.php index 87a03ba..0fa0d26 100644 --- a/storage/framework/views/62189f3220916d712cf7f502e6685f44.php +++ b/storage/framework/views/62189f3220916d712cf7f502e6685f44.php @@ -44,7 +44,7 @@
    - +
    - -
    @@ -63,8 +61,6 @@ ایجاد مدیر
    - -
    @@ -258,22 +254,17 @@ unset($__errorArgs, $__bag); ?> has($__errorArgs[0])) : if (isset($message)) { $__messageOriginal = $message; } $message = $__bag->first($__errorArgs[0]); ?> - + - + -
    +
    @@ -356,14 +347,18 @@ unset($__errorArgs, $__bag); ?>
    addLoop($__currentLoopData); foreach($__currentLoopData as $permission): $__env->incrementLoopIndices(); $loop = $__env->getLastLoop(); ?> +
    +
    +
    - getBag($__errorArgs[1] ?? 'default'); if ($__bag->has($__errorArgs[0])) : if (isset($message)) { $__messageOriginal = $message; } $message = $__bag->first($__errorArgs[0]); ?> -
    - - + + - -
    + getBag($__errorArgs[1] ?? 'default'); if ($__bag->has($__errorArgs[0])) : if (isset($message)) { $__messageOriginal = $message; } $message = $__bag->first($__errorArgs[0]); ?> -
    - - + + - -
    + onchange="previewAvatar(this)" > +
    @@ -509,29 +500,63 @@ unset($__errorArgs, $__bag); ?>
    stopSection(); ?> - - startPush('scripts'); ?> - + + roleSelect.addEventListener( + 'change', + handleAdminPermissions + ); + + + handleAdminPermissions(); + + }); + + stopPush(); ?> make('admin.layouts.app', array_diff_key(get_defined_vars(), ['__data' => 1, '__path' => 1]))->render(); ?> \ No newline at end of file diff --git a/storage/framework/views/945546a0bb70eafbd9d633e2e262f122.php b/storage/framework/views/945546a0bb70eafbd9d633e2e262f122.php index 71c0bfc..dd95c62 100644 --- a/storage/framework/views/945546a0bb70eafbd9d633e2e262f122.php +++ b/storage/framework/views/945546a0bb70eafbd9d633e2e262f122.php @@ -14,7 +14,9 @@ startSection('content'); ?>
    - + + +
    diff --git a/storage/framework/views/ee09876db1d012ea2d4abc34d2bf5030.php b/storage/framework/views/ee09876db1d012ea2d4abc34d2bf5030.php new file mode 100644 index 0000000..5317534 --- /dev/null +++ b/storage/framework/views/ee09876db1d012ea2d4abc34d2bf5030.php @@ -0,0 +1,188 @@ +startSection('breadcrumb'); ?> +
    +
    +

    مدیران حذف شده

    +
    + +
    +
    +
    +stopSection(); ?> + +startSection('content'); ?> +
    + +
    +
    +
    +
    +
    + +
    +
    + مدیران حذف‌شده +
    +
    + + + +
    +
    +
    +
    +
    + +
    +
    +
    +
    + + + + + + + + + + + + + + + + + + + + + + any()): ?> + + + + + + addLoop($__currentLoopData); foreach($__currentLoopData as $admin): $__env->incrementLoopIndices(); $loop = $__env->getLastLoop(); $__empty_1 = false; ?> + + + + + + + + + + + + + + + + + + popLoop(); $loop = $__env->getLastLoop(); if ($__empty_1): ?> + + + + + + +
    تصویرنام و نام خانوادگینام کاربریایمیلنوع حسابتاریخ ثبتتاریخ حذفعملیات
    + +
    + all(); $__env->addLoop($__currentLoopData); foreach($__currentLoopData as $error): $__env->incrementLoopIndices(); $loop = $__env->getLastLoop(); ?> +
    + popLoop(); $loop = $__env->getLastLoop(); ?> +
    + + <?php echo e($admin->first_name); ?> <?php echo e($admin->last_name); ?> + + + first_name); ?> last_name); ?> + + + username); ?> + + + email ?: '-'); ?> + + + is_super): ?> + مدیر کل + + مدیر عادی + + + created_at->toJalali()->format('H:i Y/m/d')); ?> + + + deleted_at?->toJalali()->format('H:i Y/m/d')); ?> + + +
    + + + + + + + +
    + + + + +
    + +
    +
    + مدیری در سطل زباله وجود ندارد. +
    + + +
    +
    +
    +
    + +
    +stopSection(); ?> + +make('admin.layouts.app', array_diff_key(get_defined_vars(), ['__data' => 1, '__path' => 1]))->render(); ?> \ No newline at end of file diff --git a/storage/framework/views/eef00d2e3a9c515499bd90866b295b14.php b/storage/framework/views/eef00d2e3a9c515499bd90866b295b14.php index 57877b6..35d4018 100644 --- a/storage/framework/views/eef00d2e3a9c515499bd90866b295b14.php +++ b/storage/framework/views/eef00d2e3a9c515499bd90866b295b14.php @@ -49,19 +49,13 @@ - user()?->role == \App\Enums\Admin\AdminRole::SUPERADMIN): ?> -
  • + user()?->isSuperAdmin()): ?> +
  • - - - + class="side-menu__item "> + + + مدیریت مدیران
  • @@ -69,91 +63,37 @@ -
  • - - - - - - - مدیریت کاربران - -
  • + user()?->canAccess('manage-users')): ?> +
  • + + + مدیریت کاربران + +
  • +
  • - - - - - مدیریت محصولات + + + مدیریت تورها
  • + user()?->canAccess('manage-flights')): ?>
  • - - - - - - - - - مدیریت دسته‌بندی‌ها - -
  • - - - -
  • - - - - مدیریت پیام ها - -
  • - - - -
  • - - - - مدیریت سوالات متداول - -
  • - - - -
  • - - - - مدیریت اسلایدر + + + مدیریت پروازها
  • + @@ -167,18 +107,6 @@ - -
  • - - - - - تنظیمات داده های تصویری - -
  • - -
  • - + خروج از حساب کاربری