From e6f3fcbb4edf3004d24a200a0cceec8cb57ab3e0 Mon Sep 17 00:00:00 2001 From: "c.girardi" Date: Wed, 21 Feb 2024 16:56:08 +0100 Subject: [PATCH] Implement roles management; Add user profile; Improve Ui; Clean code; Minor fix; Typo; --- app/Console/Kernel.php | 3 +- app/Http/Controllers/RolesController.php | 92 +++++++++-- app/Http/Controllers/UsersController.php | 25 ++- app/Http/Requests/StoreRoleRequest.php | 29 ++++ app/Http/Requests/UpdateRoleRequest.php | 29 ++++ app/Http/Requests/UpdateUserRequest.php | 3 +- app/Jobs/SendMailJob.php | 34 ++++ app/Mail/WelcomeEmail.php | 69 ++++++++ app/Models/User.php | 1 + .../2014_10_12_000000_create_users_table.php | 1 + .../2024_02_21_104558_create_jobs_table.php | 32 ++++ database/seeders/PermissionSeeder.php | 3 - database/seeders/RoleSeeder.php | 4 +- resources/views/emails/welcome.blade.php | 3 + resources/views/layouts/app.blade.php | 8 +- .../layouts/partials/flesh-message.blade.php | 35 ++++ .../views/layouts/partials/navbar.blade.php | 22 ++- .../views/layouts/partials/scripts.blade.php | 1 + .../views/layouts/partials/sidebar.blade.php | 38 +++-- .../views/layouts/partials/styles.blade.php | 2 + resources/views/roles/create.blade.php | 64 ++++++++ resources/views/roles/edit.blade.php | 62 +++++++ resources/views/roles/index.blade.php | 57 +++++++ resources/views/roles/show.blade.php | 35 ++++ resources/views/test.blade.php | 13 -- resources/views/users/create.blade.php | 29 +++- resources/views/users/edit.blade.php | 152 ++++++++++-------- 27 files changed, 708 insertions(+), 138 deletions(-) create mode 100644 app/Http/Requests/StoreRoleRequest.php create mode 100644 app/Http/Requests/UpdateRoleRequest.php create mode 100644 app/Jobs/SendMailJob.php create mode 100644 app/Mail/WelcomeEmail.php create mode 100644 database/migrations/2024_02_21_104558_create_jobs_table.php create mode 100644 resources/views/emails/welcome.blade.php create mode 100644 resources/views/layouts/partials/flesh-message.blade.php create mode 100644 resources/views/roles/create.blade.php create mode 100644 resources/views/roles/edit.blade.php create mode 100644 resources/views/roles/index.blade.php create mode 100644 resources/views/roles/show.blade.php delete mode 100644 resources/views/test.blade.php diff --git a/app/Console/Kernel.php b/app/Console/Kernel.php index e6b9960..24b7416 100644 --- a/app/Console/Kernel.php +++ b/app/Console/Kernel.php @@ -2,6 +2,7 @@ namespace App\Console; +use App\Jobs\SendMailJob; use Illuminate\Console\Scheduling\Schedule; use Illuminate\Foundation\Console\Kernel as ConsoleKernel; @@ -12,7 +13,7 @@ class Kernel extends ConsoleKernel */ protected function schedule(Schedule $schedule): void { - // $schedule->command('inspire')->hourly(); + //$schedule->job(new SendMailJob(null))->everyTenSeconds(); } /** diff --git a/app/Http/Controllers/RolesController.php b/app/Http/Controllers/RolesController.php index 712dba8..9988689 100644 --- a/app/Http/Controllers/RolesController.php +++ b/app/Http/Controllers/RolesController.php @@ -2,16 +2,33 @@ namespace App\Http\Controllers; +use App\Http\Requests\StoreRoleRequest; +use App\Http\Requests\UpdateRoleRequest; use Illuminate\Http\Request; +use Illuminate\Support\Facades\DB; +use Spatie\Permission\Models\Permission; +use Spatie\Permission\Models\Role; class RolesController extends Controller { + + public function __construct() + { + $this->middleware('auth'); + $this->middleware('permission:create-role|edit-role|delete-role', ['only' => ['index', 'show']]); + $this->middleware('permission:create-role', ['only' => ['create', 'store']]); + $this->middleware('permission:edit-role', ['only' => ['edit', 'update']]); + $this->middleware('permission:delete-role', ['only' => ['destroy']]); + } + /** * Display a listing of the resource. */ public function index() { - // + return view('roles.index', [ + 'roles' => Role::orderBy('id', 'DESC')->paginate(3) + ]); } /** @@ -19,46 +36,91 @@ class RolesController extends Controller */ public function create() { - // + return view('roles.create', [ + 'permissions' => Permission::get() + ]); } /** * Store a newly created resource in storage. */ - public function store(Request $request) + public function store(StoreRoleRequest $request) { - // + $role = Role::create(['name' => $request->name]); + + $permissions = Permission::whereIn('id', $request->permissions)->get(['name'])->toArray(); + + $role->syncPermissions($permissions); + + return redirect()->route('roles.index') + ->withSuccess('New role is added successfully.'); } /** * Display the specified resource. */ - public function show(string $id) + public function show(Role $role) { - // + $rolePermissions = Permission::join("role_has_permissions", "permission_id", "=", "id") + ->where("role_id", $role->id) + ->select('name') + ->get(); + return view('roles.show', [ + 'role' => $role, + 'rolePermissions' => $rolePermissions + ]); } /** * Show the form for editing the specified resource. */ - public function edit(string $id) + public function edit(Role $role) { - // + if ($role->name == 'ADMIN') { + abort(403, 'ADMIN ROLE CAN NOT BE EDITED'); + } + + $rolePermissions = DB::table("role_has_permissions")->where("role_id", $role->id) + ->pluck('permission_id') + ->all(); + + return view('roles.edit', [ + 'role' => $role, + 'permissions' => Permission::get(), + 'rolePermissions' => $rolePermissions + ]); } - /** - * Update the specified resource in storage. - */ - public function update(Request $request, string $id) + public function update(UpdateRoleRequest $request, Role $role) { - // + $input = $request->only('name'); + + $role->update($input); + + $permissions = Permission::whereIn('id', $request->permissions)->get(['name'])->toArray(); + + $role->syncPermissions($permissions); + + return redirect()->back() + ->withSuccess('Role is updated successfully.'); } /** * Remove the specified resource from storage. */ - public function destroy(string $id) + /** + * Remove the specified resource from storage. + */ + public function destroy(Role $role) { - // + if($role->name=='ADMIn'){ + abort(403, 'ADMIN ROLE CAN NOT BE DELETED'); + } + if(auth()->user()->hasRole($role->name)){ + abort(403, 'CAN NOT DELETE SELF ASSIGNED ROLE'); + } + $role->delete(); + return redirect()->route('roles.index') + ->withSuccess('Role is deleted successfully.'); } } diff --git a/app/Http/Controllers/UsersController.php b/app/Http/Controllers/UsersController.php index b68546e..569433d 100644 --- a/app/Http/Controllers/UsersController.php +++ b/app/Http/Controllers/UsersController.php @@ -4,9 +4,11 @@ namespace App\Http\Controllers; use App\Http\Requests\StoreUserRequest; use App\Http\Requests\UpdateUserRequest; +use App\Jobs\SendMailJob; use App\Models\User; use Illuminate\Http\Request; use Illuminate\Support\Facades\Hash; +use Illuminate\Support\Facades\Mail; use Spatie\Permission\Models\Role; class UsersController extends Controller @@ -62,6 +64,7 @@ class UsersController extends Controller */ public function show(User $user) { + //dispatch(new SendMailJob($user)); return view('users.show', [ 'user' => $user ]); @@ -72,9 +75,9 @@ class UsersController extends Controller */ public function edit(User $user) { - // Check Only Super Admin can update his own Profile - if ($user->hasRole('ADMIN')){ - if($user->id != auth()->user()->id){ + // Check Only ADMIN can update his own Profile + if ($user->hasRole('ADMIN')) { + if ($user->id != auth()->user()->id) { abort(403, 'USER DOES NOT HAVE THE RIGHT PERMISSIONS'); } } @@ -93,12 +96,19 @@ class UsersController extends Controller { $input = $request->all(); - if(!empty($request->password)){ + if (!empty($request->password)) { $input['password'] = Hash::make($request->password); - }else{ + } else { $input = $request->except('password'); } + + if ($request->hasFile('image')) { + $filename = $request->image->getClientOriginalName(); + $request->image->storeAs('images', $filename, 'public'); + $input['image'] = $filename; + } + $user->update($input); $user->syncRoles($request->roles); @@ -112,9 +122,8 @@ class UsersController extends Controller */ public function destroy(User $user) { - // About if user is Super Admin or User ID belongs to Auth User - if ($user->hasRole('ADMIN') || $user->id == auth()->user()->id) - { + // About if user is ADMIN or User ID belongs to Auth User + if ($user->hasRole('ADMIN') || $user->id == auth()->user()->id) { abort(403, 'USER DOES NOT HAVE THE RIGHT PERMISSIONS'); } diff --git a/app/Http/Requests/StoreRoleRequest.php b/app/Http/Requests/StoreRoleRequest.php new file mode 100644 index 0000000..e31aa80 --- /dev/null +++ b/app/Http/Requests/StoreRoleRequest.php @@ -0,0 +1,29 @@ +|string> + */ + public function rules(): array + { + return [ + 'name' => 'required|string|max:250|unique:roles,name', + 'permissions' => 'required', + ]; + } +} diff --git a/app/Http/Requests/UpdateRoleRequest.php b/app/Http/Requests/UpdateRoleRequest.php new file mode 100644 index 0000000..03d3f19 --- /dev/null +++ b/app/Http/Requests/UpdateRoleRequest.php @@ -0,0 +1,29 @@ +|string> + */ + public function rules(): array + { + return [ + 'name' => 'required|string|max:250|unique:roles,name,'.$this->role->id, + 'permissions' => 'required', + ]; + } +} diff --git a/app/Http/Requests/UpdateUserRequest.php b/app/Http/Requests/UpdateUserRequest.php index d98534b..593c11b 100644 --- a/app/Http/Requests/UpdateUserRequest.php +++ b/app/Http/Requests/UpdateUserRequest.php @@ -25,7 +25,8 @@ class UpdateUserRequest extends FormRequest 'name' => 'required|string|max:250', 'email' => 'required|string|email:rfc,dns|max:250|unique:users,email,'.$this->user->id, 'password' => 'nullable|string|min:8|confirmed', - 'roles' => 'required' + 'roles' => 'required', + 'image' => 'file|image' ]; } } diff --git a/app/Jobs/SendMailJob.php b/app/Jobs/SendMailJob.php new file mode 100644 index 0000000..c705782 --- /dev/null +++ b/app/Jobs/SendMailJob.php @@ -0,0 +1,34 @@ +user = $user; + } + + /** + * Execute the job. + */ + public function handle(): void + { + Mail::to($this->user->email) + ->send(new \App\Mail\WelcomeEmail($this->user)); + } +} diff --git a/app/Mail/WelcomeEmail.php b/app/Mail/WelcomeEmail.php new file mode 100644 index 0000000..a29e044 --- /dev/null +++ b/app/Mail/WelcomeEmail.php @@ -0,0 +1,69 @@ + 'Motula-Translate', + ], + ); + } + + /** + * Get the message envelope. + */ + public function envelope(): Envelope + { + return new Envelope( + subject: 'Welcome Email', + ); + } + + + /** + * Get the message content definition. + */ + public function content(): Content + { + return new Content( + view: 'emails.welcome', + ); + } + + /** + * Get the attachments for the message. + * + * @return array + */ + public function attachments(): array + { + return []; + } +} diff --git a/app/Models/User.php b/app/Models/User.php index 8201eaf..f74b7eb 100644 --- a/app/Models/User.php +++ b/app/Models/User.php @@ -24,6 +24,7 @@ class User extends Authenticatable 'name', 'email', 'password', + 'image' ]; /** diff --git a/database/migrations/2014_10_12_000000_create_users_table.php b/database/migrations/2014_10_12_000000_create_users_table.php index 444fafb..9f9ebda 100644 --- a/database/migrations/2014_10_12_000000_create_users_table.php +++ b/database/migrations/2014_10_12_000000_create_users_table.php @@ -17,6 +17,7 @@ return new class extends Migration $table->string('email')->unique(); $table->timestamp('email_verified_at')->nullable(); $table->string('password'); + $table->string('image')->nullable(); $table->rememberToken(); $table->timestamps(); }); diff --git a/database/migrations/2024_02_21_104558_create_jobs_table.php b/database/migrations/2024_02_21_104558_create_jobs_table.php new file mode 100644 index 0000000..6098d9b --- /dev/null +++ b/database/migrations/2024_02_21_104558_create_jobs_table.php @@ -0,0 +1,32 @@ +bigIncrements('id'); + $table->string('queue')->index(); + $table->longText('payload'); + $table->unsignedTinyInteger('attempts'); + $table->unsignedInteger('reserved_at')->nullable(); + $table->unsignedInteger('available_at'); + $table->unsignedInteger('created_at'); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('jobs'); + } +}; diff --git a/database/seeders/PermissionSeeder.php b/database/seeders/PermissionSeeder.php index 7cefd63..2425f82 100644 --- a/database/seeders/PermissionSeeder.php +++ b/database/seeders/PermissionSeeder.php @@ -20,9 +20,6 @@ class PermissionSeeder extends Seeder 'create-user', 'edit-user', 'delete-user', - 'create-product', - 'edit-product', - 'delete-product' ]; // Looping and Inserting Array's Permissions into Permission Table diff --git a/database/seeders/RoleSeeder.php b/database/seeders/RoleSeeder.php index c3e8c56..3a28d98 100644 --- a/database/seeders/RoleSeeder.php +++ b/database/seeders/RoleSeeder.php @@ -14,13 +14,11 @@ class RoleSeeder extends Seeder public function run(): void { $admin = Role::create(['name' => 'ADMIN']); + $admin = Role::create(['name' => 'MANAGER']); $admin->givePermissionTo([ 'create-user', 'edit-user', 'delete-user', - 'create-product', - 'edit-product', - 'delete-product' ]); } } diff --git a/resources/views/emails/welcome.blade.php b/resources/views/emails/welcome.blade.php new file mode 100644 index 0000000..61edc9d --- /dev/null +++ b/resources/views/emails/welcome.blade.php @@ -0,0 +1,3 @@ +
+ Price: {{ $user->username }} +
diff --git a/resources/views/layouts/app.blade.php b/resources/views/layouts/app.blade.php index 8d9cb28..63b432b 100644 --- a/resources/views/layouts/app.blade.php +++ b/resources/views/layouts/app.blade.php @@ -5,7 +5,7 @@ - {{ config('app.name', 'Laravel') }} + {{ config('app.name', 'Motula-Translate') }} @@ -20,6 +20,9 @@ 'resources/vendors/flatpickr/flatpickr.min.css', 'resources/vendors/fontawesome/css/all.min.css', ]) + + @include('layouts.partials.styles') + @stack('head-scripts')
@@ -28,6 +31,7 @@
@include('layouts.partials.navbar')
+ @include('layouts.partials.flesh-message') {{ $slot }}
@@ -36,6 +40,6 @@
@include('layouts.partials.scripts') - +@stack('body-scripts') diff --git a/resources/views/layouts/partials/flesh-message.blade.php b/resources/views/layouts/partials/flesh-message.blade.php new file mode 100644 index 0000000..94e957c --- /dev/null +++ b/resources/views/layouts/partials/flesh-message.blade.php @@ -0,0 +1,35 @@ +@if ($message = Session::get('success')) + +@endif + + +@if ($message = Session::get('error')) + +@endif + +@if ($message = Session::get('warning')) + +@endif + +@if ($message = Session::get('info')) + +@endif + +@if ($errors->any()) + +@endif diff --git a/resources/views/layouts/partials/navbar.blade.php b/resources/views/layouts/partials/navbar.blade.php index 8249a28..9ab5a7c 100644 --- a/resources/views/layouts/partials/navbar.blade.php +++ b/resources/views/layouts/partials/navbar.blade.php @@ -233,14 +233,24 @@ --}} - - + +
diff --git a/resources/views/layouts/partials/styles.blade.php b/resources/views/layouts/partials/styles.blade.php index e69de29..f512486 100644 --- a/resources/views/layouts/partials/styles.blade.php +++ b/resources/views/layouts/partials/styles.blade.php @@ -0,0 +1,2 @@ + + diff --git a/resources/views/roles/create.blade.php b/resources/views/roles/create.blade.php new file mode 100644 index 0000000..80afa8a --- /dev/null +++ b/resources/views/roles/create.blade.php @@ -0,0 +1,64 @@ + +
+
+
+ Add New Role +
+
+ ← Back +
+
+
+
+ @csrf + +
+ +
+ + @if ($errors->has('name')) + {{ $errors->first('name') }} + @endif +
+
+ +
+ +
+ + @if ($errors->has('permissions')) + {{ $errors->first('permissions') }} + @endif +
+
+ +
+ +
+ +
+
+
+ @push('body-scripts') + + @endpush +
+ + diff --git a/resources/views/roles/edit.blade.php b/resources/views/roles/edit.blade.php new file mode 100644 index 0000000..4f7c6e4 --- /dev/null +++ b/resources/views/roles/edit.blade.php @@ -0,0 +1,62 @@ + +
+
+
+ Edit Role +
+
+ ← Back +
+
+
+
+ @csrf + @method("PUT") + +
+ +
+ + @if ($errors->has('name')) + {{ $errors->first('name') }} + @endif +
+
+ +
+ +
+ + @if ($errors->has('permissions')) + {{ $errors->first('permissions') }} + @endif +
+
+ +
+ +
+ +
+
+
+ @push('body-scripts') + + @endpush +
diff --git a/resources/views/roles/index.blade.php b/resources/views/roles/index.blade.php new file mode 100644 index 0000000..a135638 --- /dev/null +++ b/resources/views/roles/index.blade.php @@ -0,0 +1,57 @@ + +
+
Manage Roles
+
+ @can('create-role') + Add New Role + @endcan + + + + + + + + + + @forelse ($roles as $role) + + + + + + @empty + + @endforelse + +
S#NameAction
{{ $loop->iteration }}{{ $role->name }} +
+ @csrf + @method('DELETE') + + Show + + @if ($role->name!='ADMIN') + @can('edit-role') + Edit + @endcan + + @can('delete-role') + @if ($role->name!=Auth::user()->hasRole($role->name)) + + @endif + @endcan + @endif + +
+
+ + No Role Found! + +
+ + {{ $roles->links() }} + +
+
+
diff --git a/resources/views/roles/show.blade.php b/resources/views/roles/show.blade.php new file mode 100644 index 0000000..6f985ca --- /dev/null +++ b/resources/views/roles/show.blade.php @@ -0,0 +1,35 @@ + +
+
+
+ Role Information +
+
+ ← Back +
+
+
+ +
+ +
+ {{ $role->name }} +
+
+ +
+ +
+ @if ($role->name=='ADMIN') + All + @else + @forelse ($rolePermissions as $permission) + {{ $permission->name }} + @empty + @endforelse + @endif +
+
+
+
+
diff --git a/resources/views/test.blade.php b/resources/views/test.blade.php deleted file mode 100644 index 6df8315..0000000 --- a/resources/views/test.blade.php +++ /dev/null @@ -1,13 +0,0 @@ -@if (session('status')) -
- {{ session('status') }} -
-@endif - - -Bla Bla Bla - - -{{$name}} - - diff --git a/resources/views/users/create.blade.php b/resources/views/users/create.blade.php index 822fd55..0db3962 100644 --- a/resources/views/users/create.blade.php +++ b/resources/views/users/create.blade.php @@ -9,7 +9,7 @@
-
+ @csrf
@@ -59,17 +59,17 @@
- + @if ($errors->has('image')) + {{ $errors->first('image') }} + @endif +
+
+
@@ -94,4 +104,15 @@
+ @push('body-scripts') + + @endpush + + + diff --git a/resources/views/users/edit.blade.php b/resources/views/users/edit.blade.php index e9b51e5..4e37ad6 100644 --- a/resources/views/users/edit.blade.php +++ b/resources/views/users/edit.blade.php @@ -7,92 +7,112 @@ -
-
- @csrf - @method("PUT") +
+
+ + @csrf + @method("PUT") -
- -
- - @if ($errors->has('name')) - {{ $errors->first('name') }} - @endif -
+
+ +
+ + @if ($errors->has('name')) + {{ $errors->first('name') }} + @endif
+
-
- -
- - @if ($errors->has('email')) - {{ $errors->first('email') }} - @endif -
+
+ +
+ + @if ($errors->has('email')) + {{ $errors->first('email') }} + @endif
+
-
- -
- - @if ($errors->has('password')) - {{ $errors->first('password') }} - @endif -
+
+ +
+ + @if ($errors->has('password')) + {{ $errors->first('password') }} + @endif
+
-
- -
- -
+
+ +
+
+
-
- -
- + @forelse ($roles as $role) - @if ($role!='Super Admin') + @if ($role!='ADMIN') + + @else + @if (Auth::user()->hasRole('ADMIN')) - @else - @if (Auth::user()->hasRole('Super Admin')) - - @endif @endif + @endif - @empty + @empty - @endforelse - - @if ($errors->has('roles')) - {{ $errors->first('roles') }} - @endif -
+ @endforelse + + @if ($errors->has('roles')) + {{ $errors->first('roles') }} + @endif
+
-
- +
+ +
+ + @if ($errors->has('image')) + {{ $errors->first('image') }} + @endif
+
- -
+
+ + +
+ +
- +
+ @push('body-scripts') + + @endpush +