In this part we will create the roles and permissions modules using the same technique that we followed in the previous tutorial.
Series Topics:
- Part 1: Preparation
- Part 2: Database
- Part 3: Models & Relations
- Part 4: Preparing Login Page
- Part 5: Users Module
- Part 6: Roles & Permissions
- Part 7: Documents Module
- Part 8: Contacts Module
- Part 9: Tasks Module
- Part 10: Mailbox Module
- Part 11: Mailbox Module Complete
- Part 12: Calendar Module
- Part 13: Finishing
In part 1 we installed the roles and permissions package, this package have several tables in the database to enable us to store roles and permissions in their dedicated tables so in this part we will add two modules that control the permissions and roles.
The first module we will add is the permissions module and it will store the permissions like “add_contact” permission.
The second one is the roles module, the roles contain many permission, for example role “sales person” will have permissions view contact, view tasks, view documents etc.
After that we will add another page in the users module to enable it to select the role(s).
Note that the permissions and roles modules will be controlled by the super admin only “is_admin=1”.
Generating Permissions Module
We will use the same commands we used in the previous part to generate the views and controllers.
At first modify app/Http/Kernel.php and modify $routeMiddleware
protected $routeMiddleware = [ 'auth' => \Illuminate\Auth\Middleware\Authenticate::class, 'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class, 'bindings' => \Illuminate\Routing\Middleware\SubstituteBindings::class, 'cache.headers' => \Illuminate\Http\Middleware\SetCacheHeaders::class, 'can' => \Illuminate\Auth\Middleware\Authorize::class, 'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class, 'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class, 'admin' => \App\Http\Middleware\Administrator::class, 'permission' => \Spatie\Permission\Middlewares\PermissionMiddleware::class ];
Generate the views:
php artisan crud:view permissions --fields="name#string" --view-path="pages" --route-group=admin --form-helper=html --validations="name#required"
Generate the controller:
php artisan crud:controller PermissionsController --crud-name=permissions --model-name=Permission --model-namespace="Spatie\\Permission\\Models\\" --view-path="pages" --route-group=admin
Permissions Controller
Open app/Http/Controllers/PermissionsController.php and make the below updates
<?php namespace App\Http\Controllers; use App\Http\Controllers\Controller; use Spatie\Permission\Models\Permission; use Illuminate\Http\Request; class PermissionsController extends Controller { public function __construct() { $this->middleware('admin'); } /** * Display a listing of the resource. * * @return \Illuminate\View\View */ public function index(Request $request) { $keyword = $request->get('search'); $perPage = 25; if (!empty($keyword)) { $permissions = Permission::where('name', 'like', "%$keyword%")->paginate($perPage); } else { $permissions = Permission::latest()->paginate($perPage); } return view('pages.permissions.index', compact('permissions')); } /** * Show the form for creating a new resource. * * @return \Illuminate\View\View */ public function create() { return view('pages.permissions.create'); } /** * Store a newly created resource in storage. * * @param \Illuminate\Http\Request $request * * @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector */ public function store(Request $request) { $this->validate($request, [ 'name' => 'required|unique:permissions,name' ]); $requestData = $request->all(); Permission::create($requestData); return redirect('admin/permissions')->with('flash_message', 'Permission added!'); } /** * Display the specified resource. * * @param int $id * * @return \Illuminate\View\View */ public function show($id) { $permission = Permission::findOrFail($id); return view('pages.permissions.show', compact('permission')); } }
Permissions Views
Now open the below view files and make the following updates to each file
resources/views/pages/permissions/create.blade.php
@extends('layout.app') @section('title', ' | Create permission') @section('content') <section class="content-header"> <h1> Create New permission </h1> <ol class="breadcrumb"> <li><a href="{{ url('/admin/') }}"><i class="fa fa-dashboard"></i> Dashboard</a></li> <li><a href="{{ url('/admin/permissions') }}">Permissions</a></li> <li class="active">Create</li> </ol> </section> <section class="content"> <div class="row"> <div class="col-md-12"> <div class="card"> <div class="card-body"> <a href="{{ url('/admin/permissions') }}" title="Back"><button class="btn btn-warning btn-sm"><i class="fa fa-arrow-left" aria-hidden="true"></i> Back</button></a> <br /> <br /> @if ($errors->any()) <ul class="alert alert-danger"> @foreach ($errors->all() as $error) <li>{{ $error }}</li> @endforeach </ul> @endif <form method="POST" action="{{ url('/admin/permissions') }}" accept-charset="UTF-8" enctype="multipart/form-data"> {{ csrf_field() }} @include ('pages.permissions.form', ['formMode' => 'create']) </form> </div> </div> </div> </div> </section> @endsection
resources/views/pages/permissions/form.blade.php
<div class="form-group {{ $errors->has('name') ? 'has-error' : ''}}"> <label for="name" class="control-label">{{ 'Name' }}</label> <input class="form-control" name="name" type="text" id="name" value="{{ isset($permission->name) ? $permission->name : ''}}" required> {!! $errors->first('name', '<p class="help-block">:message</p>') !!} </div> <div class="form-group"> <input class="btn btn-primary" type="submit" value="{{ $formMode === 'edit' ? 'Update' : 'Create' }}"> </div>
resources/views/pages/permissions/index.blade.php
@extends('layout.app') @section('title', ' | List Permissions') @section('content') <section class="content-header"> <h1> Permissions </h1> <ol class="breadcrumb"> <li><a href="{{ url('/admin') }}"><i class="fa fa-dashboard"></i> Dashboard</a></li> <li class="active">Permissions</li> </ol> </section> <section class="content"> <div class="row"> <div class="col-md-12"> <div class="card"> <div class="card-body"> @include('includes.flash_message') <a href="{{ url('/admin/permissions/create') }}" class="btn btn-success btn-sm pull-right" title="Add New permission"> <i class="fa fa-plus" aria-hidden="true"></i> Add New </a> <form method="GET" action="{{ url('/admin/permissions') }}" accept-charset="UTF-8" class="form-inline my-2 my-lg-0" role="search"> <div class="input-group"> <input type="text" class="form-control" name="search" placeholder="Search..." value="{{ request('search') }}"> <span class="input-group-btn"> <button class="btn btn-secondary" type="submit"> <i class="fa fa-search"></i> </button> </span> </div> </form> <br/> <br/> <div class="table-responsive"> <table class="table"> <thead> <tr> <th>#</th><th>Name</th><th>Actions</th> </tr> </thead> <tbody> @foreach($permissions as $item) <tr> <td>{{ $item->id }}</td> <td>{{ $item->name }}</td> <td> <a href="{{ url('/admin/permissions/' . $item->id) }}" title="View permission"><button class="btn btn-info btn-sm"><i class="fa fa-eye" aria-hidden="true"></i> View</button></a> </td> </tr> @endforeach </tbody> </table> <div class="pagination-wrapper"> {!! $permissions->appends(['search' => Request::get('search')])->render() !!} </div> </div> </div> </div> </div> </div> </section> @endsection
resources/views/pages/permissions/show.blade.php
@extends('layout.app') @section('title', ' | Show permission') @section('content') <section class="content-header"> <h1> permission #{{ $permission->id }} </h1> <ol class="breadcrumb"> <li><a href="{{ url('/admin/') }}"><i class="fa fa-dashboard"></i> Dashboard</a></li> <li><a href="{{ url('/admin/permissions') }}">Permissions</a></li> <li class="active">Show</li> </ol> </section> <section class="content"> <div class="row"> <div class="col-md-12"> <div class="card"> <div class="card-body"> <a href="{{ url('/admin/permissions') }}" title="Back"><button class="btn btn-warning btn-sm"><i class="fa fa-arrow-left" aria-hidden="true"></i> Back</button></a> <br/> <br/> <div class="table-responsive"> <table class="table"> <tbody> <tr> <th>ID</th><td>{{ $permission->id }}</td> </tr> <tr><th> Name </th><td> {{ $permission->name }} </td></tr> </tbody> </table> </div> </div> </div> </div> </div> </section> @endsection
Updating Routes
routes/web.php
<?php Route::group(['prefix' => 'admin', 'middleware' => 'auth'], function () { Route::get('/', function () { return view('pages.home.index'); }); Route::resource('/users', 'UsersController'); Route::get('/my-profile', 'UsersController@getProfile'); Route::get('/my-profile/edit', 'UsersController@getEditProfile'); Route::patch('/my-profile/edit', 'UsersController@postEditProfile'); Route::resource('/permissions', 'PermissionsController'); Route::get('/forbidden', function () { return view('pages.forbidden.forbidden_area'); }); }); Route::get('/', function () { return redirect()->to('/admin'); }); Auth::routes();
Generating Roles Module
Generate the views:
php artisan crud:view roles --fields="name#string" --view-path="pages" --route-group=admin --form-helper=html --validations="name#required"
Generate the controller:
php artisan crud:controller RolesController --crud-name=roles --model-name=Role --model-namespace="Spatie\\Permission\\Models\\" --view-path="pages" --route-group=admin
Roles Controller
Open app/Http/Controller/RolesController.php and update it as shown below:
<?php namespace App\Http\Controllers; use Spatie\Permission\Models\Permission; use Spatie\Permission\Models\Role; use Illuminate\Http\Request; class RolesController extends Controller { public function __construct() { $this->middleware('admin'); } /** * Display a listing of the resource. * * @return \Illuminate\View\View */ public function index(Request $request) { $keyword = $request->get('search'); $perPage = 25; if (!empty($keyword)) { $roles = Role::where("name", "like", "%$keyword%")->paginate($perPage); } else { $roles = Role::latest()->paginate($perPage); } return view('pages.roles.index', compact('roles')); } /** * Show the form for creating a new resource. * * @return \Illuminate\View\View */ public function create() { $permissions = Permission::all(); return view('pages.roles.create', compact('permissions')); } /** * Store a newly created resource in storage. * * @param \Illuminate\Http\Request $request * * @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector */ public function store(Request $request) { $this->validate($request, [ 'name' => 'required|unique:roles,name', 'permissions' => 'required' ]); $requestData = $request->all(); $role = Role::create(['name' => $requestData['name']]); // attach permissions to role foreach ($requestData['permissions'] as $key => $value) { $role->givePermissionTo(Permission::findById($key)); } return redirect('admin/roles')->with('flash_message', 'Role added!'); } /** * Display the specified resource. * * @param int $id * * @return \Illuminate\View\View */ public function show($id) { $role = Role::findOrFail($id); return view('pages.roles.show', compact('role')); } /** * Show the form for editing the specified resource. * * @param int $id * * @return \Illuminate\View\View */ public function edit($id) { $role = Role::findOrFail($id); $permissions = Permission::all(); $selected_permissions = []; foreach ($role->permissions as $permission) { array_push($selected_permissions, $permission->id); } return view('pages.roles.edit', compact('role', 'permissions', 'selected_permissions')); } /** * Update the specified resource in storage. * * @param \Illuminate\Http\Request $request * @param int $id * * @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector */ public function update(Request $request, $id) { $this->validate($request, [ 'name' => 'required|unique:roles,name,' . $id, 'permissions' => 'required' ]); $requestData = $request->all(); $role = Role::findOrFail($id); $role->update(['name' => $requestData['name']]); // remove permissions from role foreach (Permission::all() as $permission) { $role->revokePermissionTo($permission); } // attach permissions to role foreach ($requestData['permissions'] as $key => $value) { $role->givePermissionTo(Permission::findById($key)); } return redirect('admin/roles')->with('flash_message', 'Role updated!'); } /** * Remove the specified resource from storage. * * @param int $id * * @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector */ public function destroy($id) { Role::destroy($id); return redirect('admin/roles')->with('flash_message', 'Role deleted!'); } }
Roles Views
Open and update the roles view files shown below
resources/views/pages/roles/create.blade.php
@extends('layout.app') @section('title', ' | Create role') @section('content') <section class="content-header"> <h1> Create New role </h1> <ol class="breadcrumb"> <li><a href="{{ url('/admin/') }}"><i class="fa fa-dashboard"></i> Dashboard</a></li> <li><a href="{{ url('/admin/roles') }}">Roles</a></li> <li class="active">Create</li> </ol> </section> <section class="content"> <div class="row"> <div class="col-md-12"> <div class="card"> <div class="card-body"> <a href="{{ url('/admin/roles') }}" title="Back"><button class="btn btn-warning btn-sm"><i class="fa fa-arrow-left" aria-hidden="true"></i> Back</button></a> <br /> <br /> @if ($errors->any()) <ul class="alert alert-danger"> @foreach ($errors->all() as $error) <li>{{ $error }}</li> @endforeach </ul> @endif <form method="POST" action="{{ url('/admin/roles') }}" accept-charset="UTF-8" enctype="multipart/form-data"> {{ csrf_field() }} @include ('pages.roles.form', ['formMode' => 'create']) </form> </div> </div> </div> </div> </section> @endsection @section('scripts') <script src="{{ url('theme/views/roles/form.js') }}" type="text/javascript"></script> @endsection
resources/views/pages/roles/edit.blade.php
@extends('layout.app') @section('title', ' | Edit role') @section('content') <section class="content-header"> <h1> Edit role #{{ $role->id }} </h1> <ol class="breadcrumb"> <li><a href="{{ url('/admin/') }}"><i class="fa fa-dashboard"></i> Dashboard</a></li> <li><a href="{{ url('/admin/roles') }}">Roles</a></li> <li class="active">Edit</li> </ol> </section> <section class="content"> <div class="row"> <div class="col-md-12"> <div class="card"> <div class="card-body"> <a href="{{ url('/admin/roles') }}" title="Back"><button class="btn btn-warning btn-sm"><i class="fa fa-arrow-left" aria-hidden="true"></i> Back</button></a> <br /> <br /> @if ($errors->any()) <ul class="alert alert-danger"> @foreach ($errors->all() as $error) <li>{{ $error }}</li> @endforeach </ul> @endif <form method="POST" action="{{ url('/admin/roles/' . $role->id) }}" accept-charset="UTF-8" enctype="multipart/form-data"> {{ method_field('PATCH') }} {{ csrf_field() }} @include ('pages.roles.form', ['formMode' => 'edit']) </form> </div> </div> </div> </div> </section> @endsection @section('scripts') <script src="{{ url('theme/views/roles/form.js') }}" type="text/javascript"></script> @endsection
resources/views/pages/roles/form.blade.php
<div class="form-group {{ $errors->has('name') ? 'has-error' : ''}}"> <label for="name" class="control-label">{{ 'Name' }}</label> <input class="form-control" name="name" type="text" id="name" value="{{ isset($role->name) ? $role->name : ''}}" required> {!! $errors->first('name', '<p class="help-block">:message</p>') !!} </div> <div class="row"> <div class="col-md-12"> <h3>Permissions assigned</h3> <div class="form-group"> <label for="select_all" class="control-label"> <input type="checkbox" id="select_all" value="1" class="minimal-red"> <i class="btn bg-maroon">Select / Deselect All</i> </label> </div> <div class="row"> @foreach($permissions as $permission) <div class="col-md-3"> <div class="form-group"> <label for="permission[{{$permission->id}}]" class="control-label"> <input type="checkbox" name="permissions[{{$permission->id}}]" value="1" {{ $formMode=="edit" && in_array($permission->id, $selected_permissions)?"checked":"" }} class="minimal-red permission"> {{ ucfirst(str_replace("_", " ", $permission->name)) }} </label> </div> </div> @endforeach </div> </div> </div> <div class="form-group"> <input class="btn btn-primary" type="submit" value="{{ $formMode === 'edit' ? 'Update' : 'Create' }}"> </div>
resources/views/pages/roles/index.blade.php
@extends('layout.app') @section('title', ' | List Roles') @section('content') <section class="content-header"> <h1> Roles </h1> <ol class="breadcrumb"> <li><a href="{{ url('/admin') }}"><i class="fa fa-dashboard"></i> Dashboard</a></li> <li class="active">Roles</li> </ol> </section> <section class="content"> <div class="row"> <div class="col-md-12"> <div class="card"> <div class="card-body"> @include('includes.flash_message') <a href="{{ url('/admin/roles/create') }}" class="btn btn-success btn-sm pull-right" title="Add New role"> <i class="fa fa-plus" aria-hidden="true"></i> Add New </a> <form method="GET" action="{{ url('/admin/roles') }}" accept-charset="UTF-8" class="form-inline my-2 my-lg-0" role="search"> <div class="input-group"> <input type="text" class="form-control" name="search" placeholder="Search..." value="{{ request('search') }}"> <span class="input-group-btn"> <button class="btn btn-secondary" type="submit"> <i class="fa fa-search"></i> </button> </span> </div> </form> <br/> <br/> <div class="table-responsive"> <table class="table"> <thead> <tr> <th>#</th><th>Name</th><th>Actions</th> </tr> </thead> <tbody> @foreach($roles as $item) <tr> <td>{{ $item->id }}</td> <td>{{ $item->name }}</td> <td> <a href="{{ url('/admin/roles/' . $item->id) }}" title="View role"><button class="btn btn-info btn-sm"><i class="fa fa-eye" aria-hidden="true"></i> View</button></a> <a href="{{ url('/admin/roles/' . $item->id . '/edit') }}" title="Edit role"><button class="btn btn-primary btn-sm"><i class="fa fa-pencil-square-o" aria-hidden="true"></i> Edit</button></a> <form method="POST" action="{{ url('/admin/roles' . '/' . $item->id) }}" accept-charset="UTF-8" style="display:inline"> {{ method_field('DELETE') }} {{ csrf_field() }} <button type="submit" class="btn btn-danger btn-sm" title="Delete role" onclick="return confirm('Confirm delete?')"><i class="fa fa-trash-o" aria-hidden="true"></i> Delete</button> </form> </td> </tr> @endforeach </tbody> </table> <div class="pagination-wrapper"> {!! $roles->appends(['search' => Request::get('search')])->render() !!} </div> </div> </div> </div> </div> </div> </section> @endsection
resources/views/pages/roles/show.blade.php
@extends('layout.app') @section('title', ' | Show role') @section('content') <section class="content-header"> <h1> role #{{ $role->id }} </h1> <ol class="breadcrumb"> <li><a href="{{ url('/admin/') }}"><i class="fa fa-dashboard"></i> Dashboard</a></li> <li><a href="{{ url('/admin/roles') }}">Roles</a></li> <li class="active">Show</li> </ol> </section> <section class="content"> <div class="row"> <div class="col-md-12"> <div class="card"> <div class="card-body"> <a href="{{ url('/admin/roles') }}" title="Back"><button class="btn btn-warning btn-sm"><i class="fa fa-arrow-left" aria-hidden="true"></i> Back</button></a> <a href="{{ url('/admin/roles/' . $role->id . '/edit') }}" title="Edit role"><button class="btn btn-primary btn-sm"><i class="fa fa-pencil-square-o" aria-hidden="true"></i> Edit</button></a> <form method="POST" action="{{ url('admin/roles' . '/' . $role->id) }}" accept-charset="UTF-8" style="display:inline"> {{ method_field('DELETE') }} {{ csrf_field() }} <button type="submit" class="btn btn-danger btn-sm" title="Delete role" onclick="return confirm('Confirm delete?')"><i class="fa fa-trash-o" aria-hidden="true"></i> Delete</button> </form> <br/> <br/> <div class="table-responsive"> <table class="table"> <tbody> <tr> <th>ID</th><td>{{ $role->id }}</td> </tr> <tr><th> Name </th><td> {{ $role->name }} </td></tr> <tr> <th>Permissions</th> <td> @foreach($role->permissions as $permission) <i class="btn bg-navy" style="margin: 2px">{{ ucfirst(str_replace("_", " ", $permission->name)) }}</i> @endforeach </td> </tr> </tbody> </table> </div> </div> </div> </div> </div> </section> @endsection
As you see in the Roles and Permissions controllers i have used the Roles and Permissions Api from spatie/laravel-permission package, the package gives us all the methods to work with when we need to create permissions and create roles and assigns permissions to roles.
For the permissions module i have omitted the update and delete links also i have remove the edit(), update() and destroy() functions from the permissions controller as we don’t want to allow the user to edit or delete a permission by mistake because this will lead to system failure.
In the both of controllers constructor i have set the “admin” middleware as those modules will be controlled only by the super admin user.
To assign permissions to certain role we used the package $role->givePermissionTo($permission), this will insert a record in the roles_has_permissions table with the role_id and permission_id
To retrieve the permissions for a certain role we used $role->permissions(). To delete a permission from a role we used $role->revokePermissionTo($permission) method.
Now we need to assign the roles we just created to the user, so we will create a new action in the user controller like this:
add these two methods to the end of UsersController
..... ..... ..... public function getRole($id) { $user = User::findOrFail($id); $roles = Role::all(); return view('pages.users.role', compact('user', 'roles')); } public function updateRole(Request $request, $id) { $this->validate($request, [ 'role_id' => 'required' ]); $user = User::findOrFail($id); $old_roles = $user->roles(); $user->syncRoles($request->role_id); // send role update notification if(getSetting("enable_email_notification") == 1 && $old_roles->count() > 0 && is_array($old_roles) && $old_roles[0]->id != $request->role_id) { // send notify email $this->mailer->sendUpdateRoleEmail("Your mini crm account have updated role", $user); } return redirect('admin/users')->with('flash_message', 'Role updated!'); } ... ....
resources/views/pages/users/role.blade.php
@extends('layout.app') @section('title', ' | Select role') @section('content') <section class="content-header"> <h1> Select role </h1> <ol class="breadcrumb"> <li><a href="{{ url('/admin/') }}"><i class="fa fa-dashboard"></i> Dashboard</a></li> <li><a href="{{ url('/admin/users') }}"> Users </a></li> <li class="active">Select role</li> </ol> </section> <section class="content"> <div class="row"> <div class="col-md-12"> <div class="card"> <div class="card-body"> <a href="{{ url('/admin/users') }}" title="Back"><button class="btn btn-warning btn-sm"><i class="fa fa-arrow-left" aria-hidden="true"></i> Back</button></a> <br /> <br /> @if ($errors->any()) <ul class="alert alert-danger"> @foreach ($errors->all() as $error) <li>{{ $error }}</li> @endforeach </ul> @endif <form method="POST" action="{{ url('/admin/users/role/' . $user->id) }}" accept-charset="UTF-8" enctype="multipart/form-data"> {{ csrf_field() }} {{ method_field('put') }} <div class="form-group {{ $errors->has('role_id') ? 'has-error' : ''}}"> <label for="role_id" class="control-label">{{ 'Role' }}</label> <select name="role_id" id="role_id" class="form-control"> <option value="">select role</option> @foreach($roles as $role) <option value="{{ $role->id }}" {{ isset($user->roles[0]) && $role->id == $user->roles[0]->id?"selected":"" }}>{{ $role->name }}</option> @endforeach </select> {!! $errors->first('role_id', '<p class="help-block">:message</p>') !!} </div> <div class="form-group"> <input class="btn btn-primary" type="submit" value="Update"> </div> </form> </div> </div> </div> </div> </section> @endsection
Modify resources/views/pages/users/index.blade.php
@extends('layout.app') @section('title', ' | List users') @section('content') <section class="content-header"> <h1> Users </h1> <ol class="breadcrumb"> <li><a href="{{ url('/admin') }}"><i class="fa fa-dashboard"></i> Dashboard</a></li> <li class="active">Users</li> </ol> </section> <section class="content"> <div class="row"> <div class="col-md-12"> <div class="card"> <div class="card-body"> @include('includes.flash_message') <a href="{{ url('/admin/users/create') }}" class="btn btn-success btn-sm pull-right" title="Add New user"> <i class="fa fa-plus" aria-hidden="true"></i> Add New </a> <form method="GET" action="{{ url('/admin/users') }}" accept-charset="UTF-8" class="form-inline my-2 my-lg-0" role="search"> <div class="input-group"> <input type="text" class="form-control" name="search" placeholder="Search..." value="{{ request('search') }}"> <span class="input-group-btn"> <button class="btn btn-secondary" type="submit"> <i class="fa fa-search"></i> </button> </span> </div> </form> <br/> <br/> <div class="table-responsive"> <table class="table"> <thead> <tr> <th>#</th> <th>Name</th> <th>Email</th> <th>Position Title</th> <th>Is Admin</th> <th>Active / Banned</th> <th>Role</th> <th>Actions</th> </tr> </thead> <tbody> @foreach($users as $item) <tr> <td>{{ $item->id }}</td> <td>{{ $item->name }}</td> <td>{{ $item->email }}</td> <td>{{ $item->position_title }}</td> <td>{!! $item->is_admin == 1? '<i class="fa fa-check"></i>':'<i class="fa fa-times"></i>' !!}</td> <td>{!! $item->is_active == 1? '<i class="fa fa-check"></i>':'<i class="fa fa-ban"></i>' !!}</td> <td>@if(isset($item->roles[0])) <span class="label label-success">{{ $item->roles[0]->name }}</span> @endif</td> <td> <a href="{{ url('/admin/users/' . $item->id) }}" title="View user"><button class="btn btn-info btn-sm"><i class="fa fa-eye" aria-hidden="true"></i> View</button></a> <a href="{{ url('/admin/users/' . $item->id . '/edit') }}" title="Edit user"><button class="btn btn-primary btn-sm"><i class="fa fa-pencil-square-o" aria-hidden="true"></i> Edit</button></a> <a href="{{ url('/admin/users/role/' . $item->id) }}" title="Select role"><button class="btn bg-purple btn-sm"><i class="fa fa-user" aria-hidden="true"></i> Select role</button></a> @if($item->is_admin == 0) <form method="POST" action="{{ url('/admin/users' . '/' . $item->id) }}" accept-charset="UTF-8" style="display:inline"> {{ method_field('DELETE') }} {{ csrf_field() }} <button type="submit" class="btn btn-danger btn-sm" title="Delete user" onclick="return confirm('Confirm delete?')"><i class="fa fa-trash-o" aria-hidden="true"></i> Delete</button> </form> @endif </td> </tr> @endforeach </tbody> </table> <div class="pagination-wrapper"> {!! $users->appends(['search' => Request::get('search')])->render() !!} </div> </div> </div> </div> </div> </div> </section> @endsection
Update the User model add use HasRoles trait like this:
.... .... use Spatie\Permission\Traits\HasRoles; class User extends Authenticatable { .... use HasRoles; protected $guard_name = 'web'; .... }
add this method to end of the app/Helpers/MailerFactory.php
/** * sendUpdateRoleEmail * * * @param $subject * @param $user */ public function sendUpdateRoleEmail($subject, $user) { try { $this->mailer->send("emails.update_role", ['user' => $user, 'subject' => $subject], function($message) use ($subject, $user) { $message->from($this->fromAddress, $this->fromName) ->to($user->email)->subject($subject); }); } catch (\Exception $ex) { die("Mailer Factory error: " . $ex->getMessage()); } }
resources/views/emails/update_role.blade.php
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>{{ $subject }}</title> </head> <body> <p> Hello {{ $user->name }}, </p> <p> You have been assigned to a user role "{{ $user->roles[0]->name }}" </p> </body> </html>
Modify routes/web.php add those lines after Route::resource(‘permissions’)
Route::resource('/roles', 'RolesController'); Route::get('/users/role/{id}', 'UsersController@getRole'); Route::put('/users/role/{id}', 'UsersController@updateRole');
In the above code we added the methods for updating the user role in the users controller in the UsersController::updateRole() method.
Then assigning a role to the user is acheived by calling $user->syncRoles($role_id) . This method first the removes the old roles if any then attach the new roles. After that we send a notification email to the user with the new role.
Finally we updated the users listing page to show the user role in file resources/…./users/index.blade.php.
Restricting Super Admin
Let’s restrict the the roles, permissions, and users module to the super admin user only because these modules is dangerous modules that can not be opened to anyone.
open resources/views/layout/sidebar.blade.php and modify it like this:
<!-- Left side column. contains the logo and sidebar --> <aside class="main-sidebar"> <!-- sidebar: style can be found in sidebar.less --> <section class="sidebar"> <!-- Sidebar user panel --> <div class="user-panel"> <div class="pull-left image"> @if(\Auth::user()->image != null) <img src="{{ url('uploads/users/' . \Auth::user()->image) }}" class="img-circle" alt="User Image"> @else <img src="{{ url('theme/dist/img/image_placeholder.png') }}" class="img-circle" alt="User Image"> @endif </div> <div class="pull-left info"> <p>{{ \Auth::user()->name }}</p> </div> </div> <!-- sidebar menu: : style can be found in sidebar.less --> <ul class="sidebar-menu" data-widget="tree"> <li class="header">MAIN NAVIGATION</li> <li class="{{ Request::segment(2) == ""?"active":"" }}"> <a href="{{ url('/admin') }}"> <i class="fa fa-dashboard"></i> <span>Dashboard</span> </a> </li> @if(\Auth::user()->is_admin == 1) <li class="{{ in_array(Request::segment(2), ['users', 'permissions', 'roles'])?"active":"" }} treeview"> <a href="#"> <i class="fa fa-users"></i> <span>User Management</span> <span class="pull-right-container"> <i class="fa fa-angle-left pull-right"></i> </span> </a> <ul class="treeview-menu"> <li class="{{ Request::segment(2) == "users"?"active":"" }}"> <a href="{{ url('/admin/users') }}"><i class="fa fa-user-o"></i> Users</a> </li> <li class="{{ Request::segment(2) == "permissions"?"active":"" }}"> <a href="{{ url('/admin/permissions') }}"><i class="fa fa-ban"></i> Permissions</a> </li> <li class="{{ Request::segment(2) == "roles"?"active":"" }}"> <a href="{{ url('/admin/roles') }}"><i class="fa fa-list"></i> Roles</a> </li> </ul> </li> @endif </ul> </section> <!-- /.sidebar --> </aside>
Also modify resources/views/pages/users/profile/view.blade.php like this:
@extends('layout.app') @section('title', ' | My Profile') @section('content') <section class="content-header"> <h1> My Profile </h1> </section> <section class="content"> <div class="row"> <div class="col-md-12"> <div class="card"> <div class="card-body"> @include('includes.flash_message') @if(user_can('edit_profile')) <a href="{{ url('/admin/my-profile/edit') }}" title="Edit profile"><button class="btn btn-primary btn-sm"><i class="fa fa-pencil-square-o" aria-hidden="true"></i> Edit</button></a> @endif <br/> <br/> <div class="table-responsive"> <table class="table"> <tbody> @if(!empty($user->image)) <tr> <td> <img src="{{ url('uploads/users/' . $user->image) }}" class="pull-right" width="200" height="200" /> </td> </tr> @endif <tr><th> Name </th><td> {{ $user->name }} </td> </tr><tr><th> Email </th><td> {{ $user->email }} </td></tr> <tr><th> Position Title </th><td> {{ $user->position_title }} </td></tr> <tr><th> Phone </th><td> {{ $user->phone }} </td></tr> </tbody> </table> </div> </div> </div> </div> </div> </section> @endsection
Here i showed the “edit profile” link if the user is super admin or has permission “edit_profile“.
Continue to Part 7: documents module>>>
Note that the permissions and roles modules will be controlled by the super admin only “is_admin=1”.
well, how can I give permission for certain roles, let’s say the super admin will create additional roles admin1 and admin2 and they also need to give permission to create and delete users
I think you can tweak the code a little bit to allow the super admin to create other super admins(is_admin=1) which in turn these users can create other users or you can remove the is_admin flag and depend on the roles and permissions package only.
Thanks a lot wael,
what is the point of making (create permission) functionality while all authorizations will be handle in front end ?
What do you mean?
Hello, I am new to laravel.
How do I implement this project on laravel 9?
To implement this in laravel 9 i think you have to create a fresh laravel 9 project then move the controllers and models and views and other related files one by one