diff --git a/app/Http/Controllers/RolesController.php b/app/Http/Controllers/RolesController.php index c38c1cf..f2f0027 100644 --- a/app/Http/Controllers/RolesController.php +++ b/app/Http/Controllers/RolesController.php @@ -12,6 +12,7 @@ use Modules\Usermanagement\Models\PermissionGroup; use Modules\Usermanagement\Models\Position; use Modules\Usermanagement\Models\Role; + use Exception; /** * Class RolesController @@ -31,14 +32,11 @@ * UsersController constructor. * * Initializes the user property with the authenticated user. - * + */ public function __construct() { - $this->middleware(function ($request, $next) { - $this->user = Auth::guard('web')->user(); - return $next($request); - }); - }*/ + $this->user = Auth::guard('web')->user(); + } /** * Display a listing of the resource. @@ -49,8 +47,8 @@ public function index() { // Check if the authenticated user has the required permission to view roles - if (is_null($this->user) || !$this->user->can('roles.read')) { - //abort(403, 'Sorry! You are not allowed to view roles.'); + if (is_null($this->user) || !$this->user->can('usermanagement.read')) { + abort(403, 'Sorry! You are not allowed to view roles.'); } // Fetch all roles from the database @@ -71,14 +69,14 @@ public function store(RoleRequest $request) { // Check if the authenticated user has the required permission to store roles - if (is_null($this->user) || !$this->user->can('roles.create')) { - //abort(403, 'Sorry! You are not allowed to store roles.'); + if (is_null($this->user) || !$this->user->can('usermanagement.create')) { + abort(403, 'Sorry! You are not allowed to store roles.'); } $validated = $request->validated(); - if($validated){ - try{ + if ($validated) { + try { // If no errors, save the role to the database $role = Role::create($validated); @@ -86,18 +84,22 @@ $permissions = Permission::whereIn('id', $permissions)->pluck('name')->toArray(); if (!empty($permissions)) { $role = Role::find($role->id); - try{ + try { $role->syncPermissions($permissions); - } catch (\Exception $e) { - echo json_encode(['message' => $e->getMessage(), 'success']);exit; + } catch (Exception $e) { + return redirect() + ->route('users.roles.index') + ->with('error', 'Failed to sync permissions: ' . $e->getMessage()); } } // Redirect back to the roles index with a success message return redirect()->route('users.roles.index')->with('success', 'Role created successfully.'); - } catch (\Exception $e) { + } catch (Exception $e) { // Redirect back to the roles index with an error message - return redirect()->route('users.roles.index')->with('error', 'Failed to create role. Please try again.'); + return redirect() + ->route('users.roles.index') + ->with('error', 'Failed to create role. Please try again.'); } } } @@ -111,40 +113,16 @@ public function create() { // Check if the authenticated user has the required permission to create roles - if (is_null($this->user) || !$this->user->can('roles.create')) { - //abort(403, 'Sorry! You are not allowed to create roles.'); + if (is_null($this->user) || !$this->user->can('usermanagement.create')) { + abort(403, 'Sorry! You are not allowed to create roles.'); } $permissiongroups = PermissionGroup::all(); - $positions = Position::all(); + $positions = Position::all(); // Return the view for creating a new role return view('usermanagement::roles.create', compact('permissiongroups', 'positions')); } - /** - * Display the specified resource. - * - * @param int $id - * - * @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View - * @throws \Illuminate\Auth\Access\AuthorizationException - */ - public function show($id) - { - // Check if the authenticated user has the required permission to view roles - if (is_null($this->user) || !$this->user->can('roles.read')) { - abort(403, 'Sorry! You are not allowed to view roles.'); - } - - // Fetch the specified role from the database - $role = Role::find($id); - - - - // Return the view for displaying the role - return view('usermanagement::roles.show', compact('role')); - } - /** * Show the form for editing the specified resource. * @@ -156,15 +134,15 @@ public function edit($id) { // Check if the authenticated user has the required permission to edit roles - if (is_null($this->user) || !$this->user->can('roles.update')) { - //abort(403, 'Sorry! You are not allowed to edit roles.'); + if (is_null($this->user) || !$this->user->can('usermanagement.update')) { + abort(403, 'Sorry! You are not allowed to edit roles.'); } // Fetch the specified role from the database - $role = Role::find($id); - $permissions = Permission::all(); + $role = Role::find($id); + $permissions = Permission::all(); $permissiongroups = PermissionGroup::all(); - $positions = Position::all(); + $positions = Position::all(); // Return the view for editing the role return view('usermanagement::roles.create', compact('role', 'permissions', 'permissiongroups', 'positions')); } @@ -183,13 +161,13 @@ public function update(RoleRequest $request, $id) { // Check if the authenticated user has the required permission to update roles - if (is_null($this->user) || !$this->user->can('roles.update')) { - //abort(403, 'Sorry! You are not allowed to update roles.'); + if (is_null($this->user) || !$this->user->can('usermanagement.update')) { + abort(403, 'Sorry! You are not allowed to update roles.'); } $validated = $request->validated(); - if($validated){ - try{ + if ($validated) { + try { // If no errors, update the role in the database $role = Role::find($id); $role->update($request->all()); @@ -198,19 +176,23 @@ $permissions = Permission::whereIn('id', $permissions)->pluck('name')->toArray(); if (!empty($permissions)) { $role = Role::find($role->id); - try{ + try { $role->syncPermissions($permissions); - } catch (\Exception $e) { - echo json_encode(['message' => $e->getMessage(), 'success']);exit; + } catch (Exception $e) { + return redirect() + ->route('users.roles.index') + ->with('error', 'Failed to sync permissions: ' . $e->getMessage()); } } // Redirect back to the roles index with a success message return redirect()->route('users.roles.index')->with('success', 'Role updated successfully.'); - } catch (\Exception $e) { + } catch (Exception $e) { // Redirect back to the roles index with an error message - return redirect()->route('users.roles.index')->with('error', 'Failed to update role. Please try again.'); + return redirect() + ->route('users.roles.index') + ->with('error', 'Failed to update role. Please try again.'); } } } @@ -223,21 +205,23 @@ * @return \Illuminate\Http\RedirectResponse * @throws \Illuminate\Auth\Access\AuthorizationException */ + public function destroy($id) { - // Check if the authenticated user has the required permission to delete roles - if (is_null($this->user) || !$this->user->can('roles.delete')) { - //abort(403, 'Sorry! You are not allowed to delete roles.'); + // Check if the authenticated user has the required permission to delete currencies + if (is_null($this->user) || !$this->user->can('usermanagement.delete')) { + return response()->json(['success' => false, 'message' => 'Sorry! You are not allowed to delete roles.'], 403); } - // Fetch the specified role from the database - $role = Role::find($id); + try { + // Delete from database + $currency = Role::find($id); + $currency->delete(); - // Delete the role - $role->delete(); - - // Redirect back to the roles index with a success message - echo json_encode(['message' => 'Role deleted successfully.', 'success' => true]); + return response()->json(['success' => true, 'message' => 'Role deleted successfully.']); + } catch (Exception $e) { + return response()->json(['success' => false, 'message' => 'Failed to delete role.']); + } } /** @@ -251,7 +235,7 @@ public function restore($id) { // Check if the authenticated user has the required permission to restore roles - if (is_null($this->user) || !$this->user->can('roles.restore')) { + if (is_null($this->user) || !$this->user->can('usermanagement.restore')) { abort(403, 'Sorry! You are not allowed to restore roles.'); } @@ -275,8 +259,8 @@ */ public function dataForDatatables(Request $request) { - if (is_null($this->user) || !$this->user->can('roles.read')) { - //abort(403, 'Sorry! You are not allowed to view users.'); + if (is_null($this->user) || !$this->user->can('usermanagement.read')) { + abort(403, 'Sorry! You are not allowed to view users.'); } // Retrieve data from the database @@ -287,7 +271,7 @@ $search = $request->get('search'); $query->where(function ($q) use ($search) { $q->whereRaw('LOWER(name) LIKE ?', ['%' . strtolower($search) . '%']) - ->orWhereHas('position', function($query) use ($search) { + ->orWhereHas('position', function ($query) use ($search) { $query->whereRaw('LOWER(name) LIKE ?', ['%' . strtolower($search) . '%']) ->orWhereRaw('CAST(level AS TEXT) LIKE ?', ['%' . $search . '%']); }); @@ -302,14 +286,19 @@ // Handle sorting for position-related columns if ($column === 'position_name') { $query->leftJoin('positions', 'roles.position_id', '=', 'positions.id') - ->orderBy('positions.name', $order) + ->orderByRaw('LOWER(positions.name) ' . $order) ->select('roles.*'); // Select only from roles table to avoid column conflicts } else if ($column === 'level') { $query->leftJoin('positions', 'roles.position_id', '=', 'positions.id') ->orderBy('positions.level', $order) ->select('roles.*'); // Select only from roles table to avoid column conflicts } else { - $query->orderBy($column, $order); + // Make sorting case-insensitive for string columns + if ($column === 'name') { + $query->orderByRaw('LOWER(roles.name) ' . $order); + } else { + $query->orderBy($column, $order); + } } } @@ -334,11 +323,12 @@ // Get the data for the current page $roles = $query->with('position')->get(); - // Calculate the page count - $pageCount = ceil($totalRecords/$request->get('size')); + // Calculate the page count - ensure we don't divide by zero + $pageSize = $request->get('size', 10); // Default to 10 if not provided + $pageCount = $pageSize > 0 ? ceil($totalRecords / $pageSize) : 0; // Calculate the current page number - $currentPage = 0 + 1; + $currentPage = $request->get('page') ?: 1; // Return the response data as a JSON object return response()->json([ diff --git a/tests/Feature/RolesControllerTest.php b/tests/Feature/RolesControllerTest.php new file mode 100644 index 0000000..f965d0b --- /dev/null +++ b/tests/Feature/RolesControllerTest.php @@ -0,0 +1,467 @@ +permissionGroup = PermissionGroup::create([ + 'name' => 'usermanagement', + 'slug' => 'usermanagement' + ]); + + // Create permissions with permission_group_id + Permission::create([ + 'name' => 'usermanagement.create', + 'guard_name' => 'web', + 'permission_group_id' => $this->permissionGroup->id + ]); + Permission::create([ + 'name' => 'usermanagement.read', + 'guard_name' => 'web', + 'permission_group_id' => $this->permissionGroup->id + ]); + Permission::create([ + 'name' => 'usermanagement.update', + 'guard_name' => 'web', + 'permission_group_id' => $this->permissionGroup->id + ]); + Permission::create([ + 'name' => 'usermanagement.delete', + 'guard_name' => 'web', + 'permission_group_id' => $this->permissionGroup->id + ]); + Permission::create([ + 'name' => 'usermanagement.export', + 'guard_name' => 'web', + 'permission_group_id' => $this->permissionGroup->id + ]); + Permission::create([ + 'name' => 'usermanagement.restore', + 'guard_name' => 'web', + 'permission_group_id' => $this->permissionGroup->id + ]); + + // Create admin role with all permissions + $this->adminRole = Role::create(['name' => 'admin', 'guard_name' => 'web']); + $this->adminRole->givePermissionTo(Permission::all()); + + // Create a user with admin role + $this->user = User::factory()->create(); + $this->user->assignRole($this->adminRole); + + // Create a position for testing + $this->position = Position::create([ + 'code' => 'TEST', + 'name' => 'Test Position', + 'level' => 1 + ]); + + // Create a test role for testing + $this->testRole = Role::create([ + 'name' => 'test-role', + 'guard_name' => 'web', + 'position_id' => $this->position->id + ]); + $this->testRole->givePermissionTo('usermanagement.read'); + } + + #[Test] + public function user_with_permission_can_view_roles_index() + { + $response = $this->actingAs($this->user) + ->get(route('users.roles.index')); + + $response->assertStatus(200); + } + + #[Test] + public function user_without_permission_cannot_view_roles_index() + { + // Create a role without permissions + $role = Role::create(['name' => 'viewer', 'guard_name' => 'web']); + + // Create a user with the viewer role + $user = User::factory()->create(); + $user->assignRole($role); + + $response = $this->actingAs($user) + ->get(route('users.roles.index')); + + $response->assertStatus(403); + } + + #[Test] + public function user_with_permission_can_create_role() + { + $response = $this->actingAs($this->user) + ->get(route('users.roles.create')); + + $response->assertStatus(200); + } + + #[Test] + public function user_without_permission_cannot_create_role() + { + // Create a role with only read permission + $role = Role::create(['name' => 'reader', 'guard_name' => 'web']); + $role->givePermissionTo('usermanagement.read'); + + // Create a user with the reader role + $user = User::factory()->create(); + $user->assignRole($role); + + $response = $this->actingAs($user) + ->get(route('users.roles.create')); + + $response->assertStatus(403); + } + + #[Test] + public function user_with_permission_can_store_role() + { + $permissions = Permission::where('name', 'usermanagement.read')->pluck('id')->toArray(); + + $roleData = [ + 'name' => 'New Role', + 'guard_name' => 'web', + 'position_id' => $this->position->id, + 'permissions' => $permissions + ]; + + $response = $this->actingAs($this->user) + ->post(route('users.roles.store'), $roleData); + + $response->assertRedirect(route('users.roles.index')); + $this->assertDatabaseHas('roles', [ + 'name' => 'New Role', + 'position_id' => $this->position->id + ]); + + // Check if permission was assigned + $newRole = Role::where('name', 'New Role')->first(); + $this->assertTrue($newRole->hasPermissionTo('usermanagement.read')); + } + + #[Test] + public function user_without_permission_cannot_store_role() + { + // Create a role with only read permission + $role = Role::create(['name' => 'reader', 'guard_name' => 'web']); + $role->givePermissionTo('usermanagement.read'); + + // Create a user with the reader role + $user = User::factory()->create(); + $user->assignRole($role); + + $permissions = Permission::where('name', 'usermanagement.read')->pluck('id')->toArray(); + + $roleData = [ + 'name' => 'New Role', + 'guard_name' => 'web', + 'position_id' => $this->position->id, + 'permissions' => $permissions + ]; + + $response = $this->actingAs($user) + ->post(route('users.roles.store'), $roleData); + + $response->assertStatus(403); + $this->assertDatabaseMissing('roles', ['name' => 'New Role']); + } + + #[Test] + public function user_with_permission_can_edit_role() + { + $response = $this->actingAs($this->user) + ->get(route('users.roles.edit', $this->testRole->id)); + + $response->assertStatus(200); + } + + #[Test] + public function user_without_permission_cannot_edit_role() + { + // Create a role with only read permission + $role = Role::create(['name' => 'reader', 'guard_name' => 'web']); + $role->givePermissionTo('usermanagement.read'); + + // Create a user with the reader role + $user = User::factory()->create(); + $user->assignRole($role); + + $response = $this->actingAs($user) + ->get(route('users.roles.edit', $this->testRole->id)); + + $response->assertStatus(403); + } + + #[Test] + public function user_with_permission_can_update_role() + { + $permissions = Permission::whereIn('name', ['usermanagement.read', 'usermanagement.update'])->pluck('id')->toArray(); + + $updatedData = [ + 'name' => 'Updated Role', + 'guard_name' => 'web', + 'position_id' => $this->position->id, + 'permissions' => $permissions + ]; + + $response = $this->actingAs($this->user) + ->put(route('users.roles.update', $this->testRole->id), $updatedData); + + $response->assertRedirect(route('users.roles.index')); + $this->assertDatabaseHas('roles', [ + 'id' => $this->testRole->id, + 'name' => 'Updated Role', + 'position_id' => $this->position->id + ]); + + // Check if permissions were updated + $updatedRole = Role::find($this->testRole->id); + $this->assertTrue($updatedRole->hasPermissionTo('usermanagement.read')); + $this->assertTrue($updatedRole->hasPermissionTo('usermanagement.update')); + } + + #[Test] + public function user_without_permission_cannot_update_role() + { + // Create a role with only read permission + $role = Role::create(['name' => 'reader', 'guard_name' => 'web']); + $role->givePermissionTo('usermanagement.read'); + + // Create a user with the reader role + $user = User::factory()->create(); + $user->assignRole($role); + + $permissions = Permission::whereIn('name', ['usermanagement.read', 'usermanagement.update'])->pluck('id')->toArray(); + + $updatedData = [ + 'name' => 'Updated Role', + 'guard_name' => 'web', + 'position_id' => $this->position->id, + 'permissions' => $permissions + ]; + + $response = $this->actingAs($user) + ->put(route('users.roles.update', $this->testRole->id), $updatedData); + + $response->assertStatus(403); + $this->assertDatabaseMissing('roles', [ + 'id' => $this->testRole->id, + 'name' => 'Updated Role' + ]); + } + + #[Test] + public function user_with_permission_can_delete_role() + { + $response = $this->actingAs($this->user) + ->delete(route('users.roles.destroy', $this->testRole->id)); + + // The destroy method returns JSON response + $response->assertJson([ + 'message' => 'Role deleted successfully.', + 'success' => true + ]); + + $this->assertSoftDeleted($this->testRole); + } + + #[Test] + public function user_without_permission_cannot_delete_role() + { + // Create a role with only read permission + $role = Role::create(['name' => 'reader', 'guard_name' => 'web']); + $role->givePermissionTo('usermanagement.read'); + + // Create a user with the reader role + $user = User::factory()->create(); + $user->assignRole($role); + + $response = $this->actingAs($user) + ->delete(route('users.roles.destroy', $this->testRole->id)); + + $response->assertStatus(403); + $this->assertDatabaseHas('roles', [ + 'id' => $this->testRole->id, + 'deleted_at' => null + ]); + } + + #[Test] + public function user_with_permission_can_restore_role() + { + // First soft delete the role + $this->testRole->delete(); + $this->assertSoftDeleted($this->testRole); + + $response = $this->actingAs($this->user) + ->get(route('users.roles.restore', $this->testRole->id)); + + $response->assertRedirect(route('users.roles.index')); + $this->assertDatabaseHas('roles', [ + 'id' => $this->testRole->id, + 'deleted_at' => null + ]); + } + + #[Test] + public function user_without_permission_cannot_restore_role() + { + // Create a role with only read permission + $role = Role::create(['name' => 'reader', 'guard_name' => 'web']); + $role->givePermissionTo('usermanagement.read'); + + // Create a user with the reader role + $user = User::factory()->create(); + $user->assignRole($role); + + // First soft delete the role + $this->testRole->delete(); + $this->assertSoftDeleted($this->testRole); + + $response = $this->actingAs($user) + ->get(route('users.roles.restore', $this->testRole->id)); + + $response->assertStatus(403); + $this->assertSoftDeleted($this->testRole); + } + + #[Test] + public function user_with_permission_can_access_datatables_data() + { + $response = $this->actingAs($this->user) + ->get(route('users.roles.datatables')); + + $response->assertStatus(200); + $response->assertJsonStructure([ + 'draw', + 'recordsTotal', + 'recordsFiltered', + 'pageCount', + 'page', + 'totalCount', + 'data' + ]); + } + + #[Test] + public function user_without_permission_cannot_access_datatables_data() + { + // Create a role without permissions + $role = Role::create(['name' => 'viewer', 'guard_name' => 'web']); + + // Create a user with the viewer role + $user = User::factory()->create(); + $user->assignRole($role); + + $response = $this->actingAs($user) + ->get(route('users.roles.datatables')); + + $response->assertStatus(403); + } + + #[Test] + public function user_with_permission_can_export_roles() + { + $response = $this->actingAs($this->user) + ->get(route('users.roles.export')); + + $response->assertStatus(200); + $response->assertHeader('content-type', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'); + } + + #[Test] + public function datatables_search_filters_roles_correctly() + { + // Create additional roles for testing search + Role::create([ + 'name' => 'searchable-role', + 'guard_name' => 'web', + 'position_id' => $this->position->id + ]); + + $response = $this->actingAs($this->user) + ->get(route('users.roles.datatables', ['search' => 'searchable'])); + + $response->assertStatus(200); + $responseData = json_decode($response->getContent(), true); + + // Check that the search returned the correct role + $this->assertGreaterThan(0, $responseData['recordsFiltered']); + $foundSearchableRole = false; + foreach ($responseData['data'] as $role) { + if ($role['name'] === 'searchable-role') { + $foundSearchableRole = true; + break; + } + } + $this->assertTrue($foundSearchableRole); + } + + #[Test] + public function datatables_sorting_works_correctly() + { + // Create additional roles for testing sorting + Role::create([ + 'name' => 'A-role', // Should come first in ascending order + 'guard_name' => 'web', + 'position_id' => $this->position->id + ]); + + Role::create([ + 'name' => 'Z-role', // Should come last in ascending order + 'guard_name' => 'web', + 'position_id' => $this->position->id + ]); + + // Test ascending order + $response = $this->actingAs($this->user) + ->get(route('users.roles.datatables', [ + 'sortField' => 'name', + 'sortOrder' => 'asc' + ])); + + $response->assertStatus(200); + $responseData = json_decode($response->getContent(), true); + + // Check that the first role is 'A-role' + $this->assertEquals('A-role', $responseData['data'][0]['name']); + + // Test descending order + $response = $this->actingAs($this->user) + ->get(route('users.roles.datatables', [ + 'sortField' => 'name', + 'sortOrder' => 'desc' + ])); + + $response->assertStatus(200); + $responseData = json_decode($response->getContent(), true); + + // Check that the first role is 'Z-role' + $this->assertEquals('Z-role', $responseData['data'][0]['name']); + } +}