feat: Implement admin role and permission management, employee management APIs, and user profile extensions.
This commit is contained in:
@@ -0,0 +1,170 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api\Admin\Employee;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Requests\EmployeeRequest;
|
||||
use App\Repositories\Employee\EmployeeRepositoryInterface;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Hash;
|
||||
use Spatie\Permission\Models\Role;
|
||||
|
||||
class EmployeeController extends Controller
|
||||
{
|
||||
public function __construct(
|
||||
private readonly EmployeeRepositoryInterface $employeeRepository
|
||||
) {}
|
||||
|
||||
public function index(Request $request): JsonResponse
|
||||
{
|
||||
$employees = $this->employeeRepository->filter($request->all());
|
||||
|
||||
return response()->json([
|
||||
'error' => false,
|
||||
'data' => $employees,
|
||||
]);
|
||||
}
|
||||
|
||||
public function store(EmployeeRequest $request): JsonResponse
|
||||
{
|
||||
$request->validated();
|
||||
|
||||
try {
|
||||
DB::beginTransaction();
|
||||
|
||||
$employee = $this->employeeRepository->create([
|
||||
'firstname' => $request->firstname,
|
||||
'lastname' => $request->lastname,
|
||||
'username' => $request->username,
|
||||
'email' => $request->email,
|
||||
'phone' => $request->phone,
|
||||
'birthday' => $request->birthday,
|
||||
'address' => $request->address,
|
||||
'password' => Hash::make($request->password),
|
||||
]);
|
||||
|
||||
$employee->syncRoles([$request->role]);
|
||||
|
||||
DB::commit();
|
||||
|
||||
return response()->json([
|
||||
'error' => false,
|
||||
'message' => 'Employee created successfully',
|
||||
'data' => $employee->load('roles'),
|
||||
], 201);
|
||||
} catch (\Exception $e) {
|
||||
DB::rollBack();
|
||||
return response()->json([
|
||||
'error' => true,
|
||||
'message' => $e->getMessage(),
|
||||
], 500);
|
||||
}
|
||||
}
|
||||
|
||||
public function show(int $id): JsonResponse
|
||||
{
|
||||
$employee = $this->employeeRepository->find($id);
|
||||
|
||||
if (!$employee) {
|
||||
return response()->json([
|
||||
'error' => true,
|
||||
'message' => "Can't find employee by ID #" . $id,
|
||||
], 404);
|
||||
}
|
||||
|
||||
return response()->json([
|
||||
'error' => false,
|
||||
'data' => $employee->load('roles'),
|
||||
]);
|
||||
}
|
||||
|
||||
public function update(int $id, EmployeeRequest $request): JsonResponse
|
||||
{
|
||||
$employee = $this->employeeRepository->find($id);
|
||||
|
||||
if (!$employee) {
|
||||
return response()->json([
|
||||
'error' => true,
|
||||
'message' => "Can't find employee by ID #" . $id,
|
||||
], 404);
|
||||
}
|
||||
|
||||
$request->validated();
|
||||
|
||||
try {
|
||||
DB::beginTransaction();
|
||||
|
||||
$data = [
|
||||
'firstname' => $request->firstname,
|
||||
'lastname' => $request->lastname,
|
||||
'username' => $request->username,
|
||||
'email' => $request->email,
|
||||
'phone' => $request->phone,
|
||||
'birthday' => $request->birthday,
|
||||
'address' => $request->address,
|
||||
];
|
||||
|
||||
if ($request->filled('password')) {
|
||||
$data['password'] = Hash::make($request->password);
|
||||
}
|
||||
|
||||
$this->employeeRepository->update($id, $data);
|
||||
$employee->syncRoles([$request->role]);
|
||||
|
||||
DB::commit();
|
||||
|
||||
return response()->json([
|
||||
'error' => false,
|
||||
'message' => 'Employee updated successfully',
|
||||
'data' => $this->employeeRepository->find($id)->load('roles'),
|
||||
]);
|
||||
} catch (\Exception $e) {
|
||||
DB::rollBack();
|
||||
return response()->json([
|
||||
'error' => true,
|
||||
'message' => $e->getMessage(),
|
||||
], 500);
|
||||
}
|
||||
}
|
||||
|
||||
public function destroy(int $id): JsonResponse
|
||||
{
|
||||
$employee = $this->employeeRepository->find($id);
|
||||
|
||||
if (!$employee) {
|
||||
return response()->json([
|
||||
'error' => true,
|
||||
'message' => "Can't find employee by ID #" . $id,
|
||||
], 404);
|
||||
}
|
||||
|
||||
try {
|
||||
DB::beginTransaction();
|
||||
$this->employeeRepository->delete($id);
|
||||
DB::commit();
|
||||
|
||||
return response()->json([
|
||||
'error' => false,
|
||||
'message' => 'Employee deleted successfully',
|
||||
]);
|
||||
} catch (\Exception $e) {
|
||||
DB::rollBack();
|
||||
return response()->json([
|
||||
'error' => true,
|
||||
'message' => $e->getMessage(),
|
||||
], 500);
|
||||
}
|
||||
}
|
||||
|
||||
public function roles(): JsonResponse
|
||||
{
|
||||
$roles = Role::where('guard_name', 'admin')->get(['id', 'name']);
|
||||
|
||||
return response()->json([
|
||||
'error' => false,
|
||||
'data' => $roles,
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,266 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api\Admin\Role;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Spatie\Permission\Models\Permission;
|
||||
use Spatie\Permission\Models\Role;
|
||||
|
||||
class RolePermissionController extends Controller
|
||||
{
|
||||
private function ensureFullAdmin(): bool
|
||||
{
|
||||
$user = auth('admin')->user();
|
||||
return $user && $user->hasRole('Full Administrator');
|
||||
}
|
||||
|
||||
/**
|
||||
* GET /v1/administrator/role-permissions
|
||||
* Danh sách tất cả roles (trừ Full Administrator) kèm permissions hiện tại
|
||||
*/
|
||||
public function index(): JsonResponse
|
||||
{
|
||||
if (!$this->ensureFullAdmin()) {
|
||||
return response()->json(['error' => true, 'message' => 'Bạn không có quyền truy cập'], 403);
|
||||
}
|
||||
|
||||
$roles = Role::where('guard_name', 'admin')
|
||||
->where('name', '!=', 'Full Administrator')
|
||||
->with('permissions')
|
||||
->get()
|
||||
->map(fn ($role) => [
|
||||
'id' => $role->id,
|
||||
'name' => $role->name,
|
||||
'permissions' => $role->permissions->pluck('name')->values(),
|
||||
]);
|
||||
|
||||
return response()->json([
|
||||
'error' => false,
|
||||
'data' => $roles,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* GET /v1/administrator/role-permissions/all-permissions
|
||||
* Tất cả permissions nhóm theo module
|
||||
*/
|
||||
public function allPermissions(): JsonResponse
|
||||
{
|
||||
if (!$this->ensureFullAdmin()) {
|
||||
return response()->json(['error' => true, 'message' => 'Bạn không có quyền truy cập'], 403);
|
||||
}
|
||||
|
||||
$grouped = Permission::where('guard_name', 'admin')
|
||||
->orderBy('id')
|
||||
->get(['id', 'name'])
|
||||
->groupBy(function ($p) {
|
||||
// Format: module.action (e.g., product-service.view, customer.manager)
|
||||
$parts = explode('.', $p->name);
|
||||
return $parts[0] ?? $p->name;
|
||||
})
|
||||
->map(function ($group, $module) {
|
||||
return [
|
||||
'module' => $module,
|
||||
'permissions' => $group->map(fn ($p) => [
|
||||
'id' => $p->id,
|
||||
'name' => $p->name,
|
||||
'action' => explode('.', $p->name)[1] ?? $p->name,
|
||||
])->values(),
|
||||
];
|
||||
})
|
||||
->values();
|
||||
|
||||
return response()->json([
|
||||
'error' => false,
|
||||
'data' => $grouped,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* GET /v1/administrator/role-permissions/mine
|
||||
* Trả về permissions hiệu lực của user đang đăng nhập (qua role của họ).
|
||||
* Accessible bởi mọi admin đã xác thực — không yêu cầu Full Administrator.
|
||||
*/
|
||||
public function mine(): JsonResponse
|
||||
{
|
||||
$user = auth('admin')->user();
|
||||
if (!$user) {
|
||||
return response()->json(['error' => true, 'message' => 'Unauthorized'], 401);
|
||||
}
|
||||
|
||||
$isFullAdmin = $user->hasRole('Full Administrator', 'admin');
|
||||
|
||||
return response()->json([
|
||||
'error' => false,
|
||||
'data' => [
|
||||
'isFullAdmin' => $isFullAdmin,
|
||||
'permissions' => $isFullAdmin
|
||||
? ['*']
|
||||
: $user->getAllPermissions()->pluck('name')->toArray(),
|
||||
],
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* POST /v1/administrator/role-permissions/permissions
|
||||
* Tạo một nhóm permissions mới theo module (chỉ Full Administrator)
|
||||
*/
|
||||
public function createPermissionGroup(Request $request): JsonResponse
|
||||
{
|
||||
if (!$this->ensureFullAdmin()) {
|
||||
return response()->json(['error' => true, 'message' => 'Bạn không có quyền truy cập'], 403);
|
||||
}
|
||||
|
||||
$module = trim($request->input('module', ''));
|
||||
$actions = $request->input('actions', ['view', 'create', 'edit', 'destroy', 'manager']);
|
||||
|
||||
if (!$module) {
|
||||
return response()->json(['error' => true, 'message' => 'Tên module không được trống'], 422);
|
||||
}
|
||||
|
||||
// Kiểm tra module đã tồn tại chưa
|
||||
$existing = Permission::where('guard_name', 'admin')
|
||||
->where('name', 'like', $module . '.%')
|
||||
->exists();
|
||||
|
||||
if ($existing) {
|
||||
return response()->json(['error' => true, 'message' => "Module \"{$module}\" đã tồn tại"], 422);
|
||||
}
|
||||
|
||||
$created = [];
|
||||
foreach ($actions as $action) {
|
||||
$name = $module . '.' . $action;
|
||||
$perm = Permission::firstOrCreate([
|
||||
'name' => $name,
|
||||
'guard_name' => 'admin',
|
||||
]);
|
||||
$created[] = [
|
||||
'id' => $perm->id,
|
||||
'name' => $perm->name,
|
||||
'action' => $action,
|
||||
];
|
||||
}
|
||||
|
||||
// Full Administrator tự động được cấp permissions mới
|
||||
$fullAdmin = Role::where('name', 'Full Administrator')
|
||||
->where('guard_name', 'admin')
|
||||
->first();
|
||||
if ($fullAdmin) {
|
||||
$fullAdmin->givePermissionTo(array_column($created, 'name'));
|
||||
}
|
||||
|
||||
app()[\Spatie\Permission\PermissionRegistrar::class]->forgetCachedPermissions();
|
||||
|
||||
return response()->json([
|
||||
'error' => false,
|
||||
'data' => [
|
||||
'module' => $module,
|
||||
'permissions' => $created,
|
||||
],
|
||||
], 201);
|
||||
}
|
||||
|
||||
/**
|
||||
* DELETE /v1/administrator/role-permissions/permissions/group/{module}
|
||||
* Xóa toàn bộ permissions của một module (chỉ Full Administrator)
|
||||
*/
|
||||
public function deletePermissionGroup(string $module): JsonResponse
|
||||
{
|
||||
if (!$this->ensureFullAdmin()) {
|
||||
return response()->json(['error' => true, 'message' => 'Bạn không có quyền truy cập'], 403);
|
||||
}
|
||||
|
||||
$deleted = Permission::where('guard_name', 'admin')
|
||||
->where('name', 'like', $module . '.%')
|
||||
->get();
|
||||
|
||||
if ($deleted->isEmpty()) {
|
||||
return response()->json(['error' => true, 'message' => 'Không tìm thấy nhóm quyền'], 404);
|
||||
}
|
||||
|
||||
foreach ($deleted as $perm) {
|
||||
$perm->delete();
|
||||
}
|
||||
|
||||
app()[\Spatie\Permission\PermissionRegistrar::class]->forgetCachedPermissions();
|
||||
|
||||
return response()->json([
|
||||
'error' => false,
|
||||
'message' => "Đã xóa nhóm quyền \"{$module}\"",
|
||||
'data' => ['module' => $module, 'deleted' => $deleted->count()],
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* PATCH /v1/administrator/role-permissions/permissions/{id}
|
||||
* Đổi tên một permission (chỉ Full Administrator)
|
||||
*/
|
||||
public function renamePermission(int $id, Request $request): JsonResponse
|
||||
{
|
||||
if (!$this->ensureFullAdmin()) {
|
||||
return response()->json(['error' => true, 'message' => 'Bạn không có quyền truy cập'], 403);
|
||||
}
|
||||
|
||||
$permission = Permission::where('guard_name', 'admin')->find($id);
|
||||
if (!$permission) {
|
||||
return response()->json(['error' => true, 'message' => 'Không tìm thấy permission'], 404);
|
||||
}
|
||||
|
||||
$newName = trim($request->input('name', ''));
|
||||
if (!$newName) {
|
||||
return response()->json(['error' => true, 'message' => 'Tên permission không được trống'], 422);
|
||||
}
|
||||
|
||||
if (Permission::where('guard_name', 'admin')->where('name', $newName)->where('id', '!=', $id)->exists()) {
|
||||
return response()->json(['error' => true, 'message' => 'Tên permission đã tồn tại'], 422);
|
||||
}
|
||||
|
||||
$permission->update(['name' => $newName]);
|
||||
app()[\Spatie\Permission\PermissionRegistrar::class]->forgetCachedPermissions();
|
||||
|
||||
return response()->json([
|
||||
'error' => false,
|
||||
'data' => ['id' => $permission->id, 'name' => $permission->name],
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* PUT /v1/administrator/role-permissions/{roleId}
|
||||
* Sync permissions cho một role
|
||||
*/
|
||||
public function update(int $roleId, Request $request): JsonResponse
|
||||
{
|
||||
if (!$this->ensureFullAdmin()) {
|
||||
return response()->json(['error' => true, 'message' => 'Bạn không có quyền truy cập'], 403);
|
||||
}
|
||||
|
||||
$role = Role::where('guard_name', 'admin')
|
||||
->where('name', '!=', 'Full Administrator')
|
||||
->find($roleId);
|
||||
|
||||
if (!$role) {
|
||||
return response()->json([
|
||||
'error' => true,
|
||||
'message' => 'Không tìm thấy vai trò',
|
||||
], 404);
|
||||
}
|
||||
|
||||
$permissions = $request->input('permissions', []);
|
||||
$role->syncPermissions($permissions);
|
||||
|
||||
// Xóa cache để /mine endpoint trả về permissions mới nhất
|
||||
app()[\Spatie\Permission\PermissionRegistrar::class]->forgetCachedPermissions();
|
||||
|
||||
return response()->json([
|
||||
'error' => false,
|
||||
'message' => "Đã cập nhật quyền cho vai trò \"{$role->name}\"",
|
||||
'data' => [
|
||||
'id' => $role->id,
|
||||
'name' => $role->name,
|
||||
'permissions' => $role->permissions()->pluck('name')->values(),
|
||||
],
|
||||
]);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user