Add admin permissions and roles functionality to admin

This commit is contained in:
Matteo Gheza 2024-01-11 18:44:34 +01:00
parent 4c6197a4c1
commit 61ee7a7b05
6 changed files with 141 additions and 14 deletions

View File

@ -116,4 +116,37 @@ class AdminController extends Controller
]);
}
}
public function getPermissionsAndRoles() {
if(!request()->user()->hasPermission("admin-roles-read")) abort(401);
return response()->json([
'permissions' => \App\Models\Permission::orderBy('name')->get(),
'roles' => \App\Models\Role::with('permissions:id,name')->get()
]);
}
public function updateRoles(Request $request) {
if(!request()->user()->hasPermission("admin-roles-update")) abort(401);
$request->validate([
'changes' => 'required|array',
'changes.*.roleId' => 'required|integer|exists:roles,id',
'changes.*.permissionId' => 'required|integer|exists:permissions,id'
]);
$roles = $request->input('changes');
foreach($roles as $role) {
$roleModel = \App\Models\Role::find($role['roleId']);
//If the role already has the permission, remove it, otherwise add it
if($roleModel->permissions()->where('id', $role['permissionId'])->exists()) {
$roleModel->permissions()->detach([$role['permissionId']]);
} else {
$roleModel->permissions()->attach([$role['permissionId']]);
}
}
return response()->json([
'message' => 'Roles updated successfully'
]);
}
}

View File

@ -98,6 +98,9 @@ Route::middleware('auth:sanctum')->group( function () {
Route::get('/admin/maintenanceMode', [AdminController::class, 'getMaintenanceMode']);
Route::post('/admin/maintenanceMode', [AdminController::class, 'updateMaintenanceMode']);
Route::get('/admin/permissionsAndRoles', [AdminController::class, 'getPermissionsAndRoles']);
Route::post('/admin/roles', [AdminController::class, 'updateRoles']);
});
Route::middleware('signed')->group( function () {

View File

@ -1 +1,21 @@
Roles
<div class="col-8 mx-auto table-responsive-md">
<table class="table table-bordered">
<thead>
<tr>
<th class="text-center"></th>
<th class="text-center" *ngFor="let role of roles">{{ role.name|titlecase }}</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let permission of permissions">
<td class="text-start">{{ permission.name }}</td>
<td *ngFor="let role of roles" (click)="togglePermission(role, permission)">
<span class="cross d-flex justify-content-center">
{{ doesRoleHavePermission(role, permission.id) ? '✖' : '' }}
</span>
</td>
</tr>
</tbody>
</table>
<button class="btn btn-primary position-fixed bottom-0 end-0 m-3" *ngIf="roleChanges.length > 0" (click)="saveRoleChanges()" [disabled]="roleChangesSubmitting">{{ 'save_changes'|translate|ftitlecase }}</button>
</div>

View File

@ -0,0 +1,3 @@
table {
min-width: 75% !important;
}

View File

@ -1,4 +1,12 @@
import { Component, OnInit } from '@angular/core';
import { ApiClientService } from 'src/app/_services/api-client.service';
import { TranslateService } from '@ngx-translate/core';
import Swal from 'sweetalert2';
interface RolePermissionPair {
roleId: number;
permissionId: number;
}
@Component({
selector: 'app-admin-roles',
@ -6,10 +14,81 @@ import { Component, OnInit } from '@angular/core';
styleUrls: ['./admin-roles.component.scss']
})
export class AdminRolesComponent implements OnInit {
permissions: any;
roles: any;
originalRoles: any;
constructor() { }
roleChanges: RolePermissionPair[] = [];
roleChangesSubmitting: boolean = false;
ngOnInit(): void {
constructor(private api: ApiClientService, private translateService: TranslateService) { }
getPermissionsAndRoles() {
this.api.get('admin/permissionsAndRoles').then((res: any) => {
this.permissions = res.permissions;
this.roles = res.roles;
this.originalRoles = JSON.parse(JSON.stringify(res.roles)); // Deep copy
this.roleChanges = [];
console.log(res);
}).catch((err: any) => {
console.error(err);
Swal.fire({
title: this.translateService.instant("error_title"),
text: err.error.message,
icon: 'error',
confirmButtonText: 'Ok'
});
}).finally(() => {
this.roleChangesSubmitting = false; //Because after submit response, data is reloaded
});
}
ngOnInit(): void {
this.getPermissionsAndRoles();
}
togglePermission(role: any, permission: any) {
const index = role.permissions.indexOf(role.permissions.find((p: any) => p.id == permission.id));
if (index > -1) {
// If the role has the permission, remove it
role.permissions.splice(index, 1);
} else {
// If the role doesn't have the permission, add it
role.permissions.push(permission);
}
if(
this.originalRoles.find((r: any) => r.id == role.id).permissions.length !== this.roles.find((r: any) => r.id == role.id).permissions.length &&
this.roleChanges.find((r: any) => r.roleId == role.id && r.permissionId == permission.id) == undefined
) {
this.roleChanges.push({roleId: role.id, permissionId: permission.id});
} else {
let roleChange = this.roleChanges.find((r: any) => r.roleId == role.id && r.permissionId == permission.id);
if(roleChange) this.roleChanges.splice(this.roleChanges.indexOf(roleChange), 1);
}
console.log(this.roleChanges);
}
doesRoleHavePermission(role: any, permissionId: number) {
return role.permissions.some((p: any) => p.id == permissionId)
}
saveRoleChanges() {
this.roleChangesSubmitting = true;
this.api.post('admin/roles', {
changes: this.roleChanges
}).then((res: any) => {
console.log(res);
this.getPermissionsAndRoles();
}).catch((err: any) => {
this.roleChangesSubmitting = false;
console.error(err);
Swal.fire({
title: this.translateService.instant("error_title"),
text: err.error.message,
icon: 'error',
confirmButtonText: 'Ok'
});
});
}
}

View File

@ -1,11 +1,6 @@
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { BsDatepickerModule } from 'ngx-bootstrap/datepicker';
import { MapPickerModule } from '../../../_components/map-picker/map-picker.module';
import { DatetimePickerModule } from '../../../_components/datetime-picker/datetime-picker.module';
import { BackBtnModule } from '../../../_components/back-btn/back-btn.module';
import { TranslationModule } from '../../../translation.module';
import { FirstLetterUppercasePipe } from '../../../_pipes/first-letter-uppercase.pipe';
@ -19,12 +14,6 @@ import { AdminRolesRoutingModule } from './admin-roles-routing.module';
imports: [
CommonModule,
AdminRolesRoutingModule,
FormsModule,
ReactiveFormsModule,
BsDatepickerModule.forRoot(),
MapPickerModule,
DatetimePickerModule,
BackBtnModule,
TranslationModule,
FirstLetterUppercasePipe
]