reconstruction of the project
This commit is contained in:
@@ -1,727 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api;
|
||||
|
||||
use App\Models\Configuration;
|
||||
use App\Models\Permission;
|
||||
use App\Models\Role;
|
||||
use App\Models\RolePermission;
|
||||
use App\Models\Staff;
|
||||
use App\Models\User;
|
||||
use App\Models\UserRole;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Validation\Rule;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
|
||||
class RolePermissionController extends BaseApiController
|
||||
{
|
||||
protected Role $role;
|
||||
protected Permission $permission;
|
||||
protected RolePermission $rolePermission;
|
||||
protected User $user;
|
||||
protected UserRole $userRole;
|
||||
protected Staff $staff;
|
||||
protected Configuration $config;
|
||||
protected string $schoolYear;
|
||||
protected string $semester;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
$this->role = model(Role::class);
|
||||
$this->permission = model(Permission::class);
|
||||
$this->rolePermission = model(RolePermission::class);
|
||||
$this->user = model(User::class);
|
||||
$this->userRole = model(UserRole::class);
|
||||
$this->staff = model(Staff::class);
|
||||
$this->config = model(Configuration::class);
|
||||
|
||||
$this->schoolYear = (string) ($this->config->getConfig('school_year') ?? '');
|
||||
$this->semester = (string) ($this->config->getConfig('semester') ?? '');
|
||||
}
|
||||
|
||||
/**
|
||||
* GET /api/v1/rolepermission/roles
|
||||
* List all roles with user counts
|
||||
*/
|
||||
public function roles()
|
||||
{
|
||||
$rows = DB::table('roles')
|
||||
->select('roles.id', 'roles.name', 'roles.description', DB::raw('COUNT(DISTINCT user_roles.user_id) AS user_count'))
|
||||
->leftJoin('user_roles', 'user_roles.role_id', '=', 'roles.id')
|
||||
->groupBy('roles.id', 'roles.name', 'roles.description')
|
||||
->orderBy('roles.name', 'ASC')
|
||||
->get()
|
||||
->toArray();
|
||||
|
||||
$normalized = array_map(static function ($row) {
|
||||
$row = (array) $row;
|
||||
if (!is_array($row)) {
|
||||
return [];
|
||||
}
|
||||
return [
|
||||
'id' => (int) ($row['id'] ?? 0),
|
||||
'name' => (string) ($row['name'] ?? ''),
|
||||
'description' => $row['description'] ?? null,
|
||||
'user_count' => (int) ($row['user_count'] ?? 0),
|
||||
];
|
||||
}, $rows ?? []);
|
||||
|
||||
return $this->success(['roles' => $normalized], 'Roles retrieved successfully');
|
||||
}
|
||||
|
||||
/**
|
||||
* GET /api/v1/rolepermission/roles/{id}
|
||||
* Get a single role
|
||||
*/
|
||||
public function showRole($id = null)
|
||||
{
|
||||
$role = $this->role->find($id);
|
||||
if (!$role) {
|
||||
return $this->error('Role not found', Response::HTTP_NOT_FOUND);
|
||||
}
|
||||
|
||||
return $this->success($role, 'Role retrieved successfully');
|
||||
}
|
||||
|
||||
/**
|
||||
* POST /api/v1/rolepermission/roles
|
||||
* Create a new role
|
||||
*/
|
||||
public function storeRole()
|
||||
{
|
||||
$payload = $this->payloadData();
|
||||
if (empty($payload)) {
|
||||
return $this->error('Invalid request data', Response::HTTP_BAD_REQUEST);
|
||||
}
|
||||
|
||||
$rules = [
|
||||
'name' => 'required|min:3|max:255|unique:roles,name',
|
||||
'slug' => 'nullable|max:64|unique:roles,slug',
|
||||
'description' => 'nullable|max:500',
|
||||
'dashboard_route' => ['required', 'min:1', 'max:255', 'regex:/^[a-z0-9_\/\-]+$/'],
|
||||
'priority' => 'required|integer|min:0|max:100000',
|
||||
'is_active' => 'required|in:0,1',
|
||||
];
|
||||
|
||||
$errors = $this->validateRequest($payload, $rules);
|
||||
if (!empty($errors)) {
|
||||
return $this->respondValidationError($errors);
|
||||
}
|
||||
|
||||
$rawName = trim((string) ($payload['name'] ?? ''));
|
||||
$rawSlug = trim((string) ($payload['slug'] ?? ''));
|
||||
$route = trim((string) ($payload['dashboard_route'] ?? ''));
|
||||
$desc = trim((string) ($payload['description'] ?? ''));
|
||||
$priority = (int) ($payload['priority'] ?? 0);
|
||||
$isActive = (string) ($payload['is_active'] ?? '0') === '1' ? 1 : 0;
|
||||
|
||||
$name = strtolower($rawName);
|
||||
$dashboard_route = strtolower($route);
|
||||
$description = strtolower($desc);
|
||||
|
||||
// Build slug: from input if provided, else from name
|
||||
$slug = $rawSlug !== '' ? $rawSlug : $name;
|
||||
$slug = strtolower(preg_replace('/[^a-z0-9]+/i', '_', $slug));
|
||||
$slug = trim($slug, '_');
|
||||
$slug = $this->ensureUniqueSlug($slug);
|
||||
|
||||
$data = [
|
||||
'name' => $name,
|
||||
'slug' => $slug,
|
||||
'description' => $description,
|
||||
'dashboard_route' => $dashboard_route,
|
||||
'priority' => $priority,
|
||||
'is_active' => $isActive,
|
||||
'created_at' => utc_now(),
|
||||
'updated_at' => utc_now(),
|
||||
];
|
||||
|
||||
try {
|
||||
$role = $this->role->create($data);
|
||||
return $this->success($role->toArray(), 'Role created successfully', Response::HTTP_CREATED);
|
||||
} catch (\Throwable $e) {
|
||||
log_message('error', 'Role creation error: ' . $e->getMessage());
|
||||
return $this->respondError('Failed to create role', Response::HTTP_INTERNAL_SERVER_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* PATCH /api/v1/rolepermission/roles/{id}
|
||||
* Update a role
|
||||
*/
|
||||
public function updateRole($id = null)
|
||||
{
|
||||
$role = $this->role->find($id);
|
||||
if (!$role) {
|
||||
return $this->error('Role not found', Response::HTTP_NOT_FOUND);
|
||||
}
|
||||
|
||||
$payload = $this->payloadData();
|
||||
if (empty($payload)) {
|
||||
return $this->error('Invalid request data', Response::HTTP_BAD_REQUEST);
|
||||
}
|
||||
|
||||
$rules = [
|
||||
'name' => ['required', 'min:3', 'max:255', Rule::unique('roles', 'name')->ignore($id)],
|
||||
'slug' => ['nullable', 'max:64', Rule::unique('roles', 'slug')->ignore($id)],
|
||||
'description' => 'nullable|max:500',
|
||||
'dashboard_route' => ['required', 'min:1', 'max:255', 'regex:/^[a-z0-9_\/\-]+$/'],
|
||||
'priority' => 'required|integer|min:0|max:100000',
|
||||
'is_active' => 'required|in:0,1',
|
||||
];
|
||||
|
||||
$errors = $this->validateRequest($payload, $rules);
|
||||
if (!empty($errors)) {
|
||||
return $this->respondValidationError($errors);
|
||||
}
|
||||
|
||||
$rawName = trim((string) ($payload['name'] ?? ''));
|
||||
$rawSlug = trim((string) ($payload['slug'] ?? ''));
|
||||
$route = trim((string) ($payload['dashboard_route'] ?? ''));
|
||||
$desc = trim((string) ($payload['description'] ?? ''));
|
||||
$priority = (int) ($payload['priority'] ?? 0);
|
||||
$isActive = (string) ($payload['is_active'] ?? '0') === '1' ? 1 : 0;
|
||||
|
||||
$name = strtolower($rawName);
|
||||
$dashboard_route = strtolower($route);
|
||||
$description = strtolower($desc);
|
||||
|
||||
// slug: if blank, derive from name; else normalize
|
||||
$slug = $rawSlug !== '' ? $rawSlug : $name;
|
||||
$slug = strtolower(preg_replace('/[^a-z0-9]+/i', '_', $slug));
|
||||
$slug = trim($slug, '_');
|
||||
|
||||
// Ensure unique slug if changed
|
||||
if ($slug !== $role['slug']) {
|
||||
$slug = $this->ensureUniqueSlug($slug, (int) $id);
|
||||
}
|
||||
|
||||
$data = [
|
||||
'name' => $name,
|
||||
'slug' => $slug,
|
||||
'description' => $description,
|
||||
'dashboard_route' => $dashboard_route,
|
||||
'priority' => $priority,
|
||||
'is_active' => $isActive,
|
||||
'updated_at' => utc_now(),
|
||||
];
|
||||
|
||||
try {
|
||||
$this->role->update($id, $data);
|
||||
$updatedRole = $this->role->find($id);
|
||||
return $this->success($updatedRole, 'Role updated successfully');
|
||||
} catch (\Throwable $e) {
|
||||
log_message('error', 'Role update error: ' . $e->getMessage());
|
||||
return $this->respondError('Failed to update role', Response::HTTP_INTERNAL_SERVER_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* DELETE /api/v1/rolepermission/roles/{id}
|
||||
* Delete a role
|
||||
*/
|
||||
public function deleteRole($id = null)
|
||||
{
|
||||
$role = $this->role->find($id);
|
||||
if (!$role) {
|
||||
return $this->error('Role not found', Response::HTTP_NOT_FOUND);
|
||||
}
|
||||
|
||||
try {
|
||||
$this->role->delete($id);
|
||||
return $this->success(null, 'Role deleted successfully');
|
||||
} catch (\Throwable $e) {
|
||||
log_message('error', 'Role deletion error: ' . $e->getMessage());
|
||||
return $this->respondError('Failed to delete role', Response::HTTP_INTERNAL_SERVER_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* GET /api/v1/rolepermission/permissions
|
||||
* List all permissions
|
||||
*/
|
||||
public function permissions()
|
||||
{
|
||||
$rows = $this->permission
|
||||
->select('id, name, description, created_at, updated_at')
|
||||
->orderBy('id', 'ASC')
|
||||
->findAll();
|
||||
|
||||
$normalized = array_map(static function ($row) {
|
||||
if (!is_array($row)) {
|
||||
return [];
|
||||
}
|
||||
return [
|
||||
'id' => (int) ($row['id'] ?? 0),
|
||||
'name' => (string) ($row['name'] ?? ''),
|
||||
'description' => $row['description'] ?? null,
|
||||
'created_at' => $row['created_at'] ?? null,
|
||||
'updated_at' => $row['updated_at'] ?? null,
|
||||
];
|
||||
}, $rows ?? []);
|
||||
|
||||
return $this->success(['permissions' => $normalized], 'Permissions retrieved successfully');
|
||||
}
|
||||
|
||||
/**
|
||||
* POST /api/v1/rolepermission/permissions
|
||||
* Create a new permission
|
||||
*/
|
||||
public function storePermission()
|
||||
{
|
||||
$payload = $this->payloadData();
|
||||
if (empty($payload)) {
|
||||
return $this->error('Invalid request data', Response::HTTP_BAD_REQUEST);
|
||||
}
|
||||
|
||||
$name = trim((string) ($payload['name'] ?? ''));
|
||||
|
||||
if ($name === '') {
|
||||
return $this->respondError('Permission name is required', Response::HTTP_BAD_REQUEST);
|
||||
}
|
||||
|
||||
// Check existence
|
||||
$existing = $this->permission->where('name', $name)->first();
|
||||
if ($existing) {
|
||||
return $this->success($existing, 'Permission already exists. No changes made.');
|
||||
}
|
||||
|
||||
$data = [
|
||||
'name' => $name,
|
||||
'description' => trim((string) ($payload['description'] ?? '')),
|
||||
];
|
||||
|
||||
try {
|
||||
$permission = $this->permission->create($data);
|
||||
return $this->success($permission->toArray(), 'Permission created successfully', Response::HTTP_CREATED);
|
||||
} catch (\Throwable $e) {
|
||||
log_message('error', 'Permission creation error: ' . $e->getMessage());
|
||||
return $this->respondError('Failed to create permission', Response::HTTP_INTERNAL_SERVER_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* PATCH /api/v1/rolepermission/permissions/{id}
|
||||
* Update a permission
|
||||
*/
|
||||
public function updatePermission($id = null)
|
||||
{
|
||||
$permission = $this->permission->find($id);
|
||||
if (!$permission) {
|
||||
return $this->error('Permission not found', Response::HTTP_NOT_FOUND);
|
||||
}
|
||||
|
||||
$payload = $this->payloadData();
|
||||
if (empty($payload)) {
|
||||
return $this->error('Invalid request data', Response::HTTP_BAD_REQUEST);
|
||||
}
|
||||
|
||||
$data = [
|
||||
'id' => $id,
|
||||
'name' => trim((string) ($payload['name'] ?? '')),
|
||||
'description' => trim((string) ($payload['description'] ?? '')),
|
||||
];
|
||||
|
||||
try {
|
||||
$this->permission->update($id, $data);
|
||||
$updatedPermission = $this->permission->find($id);
|
||||
return $this->success($updatedPermission, 'Permission updated successfully');
|
||||
} catch (\Throwable $e) {
|
||||
log_message('error', 'Permission update error: ' . $e->getMessage());
|
||||
return $this->respondError('Failed to update permission', Response::HTTP_INTERNAL_SERVER_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* DELETE /api/v1/rolepermission/permissions/{id}
|
||||
* Delete a permission
|
||||
*/
|
||||
public function deletePermission($id = null)
|
||||
{
|
||||
$permission = $this->permission->find($id);
|
||||
if (!$permission) {
|
||||
return $this->error('Permission not found', Response::HTTP_NOT_FOUND);
|
||||
}
|
||||
|
||||
try {
|
||||
$this->permission->delete($id);
|
||||
return $this->success(null, 'Permission deleted successfully');
|
||||
} catch (\Throwable $e) {
|
||||
log_message('error', 'Permission deletion error: ' . $e->getMessage());
|
||||
return $this->respondError('Failed to delete permission', Response::HTTP_INTERNAL_SERVER_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* GET /api/v1/rolepermission/roles/{roleId}/permissions
|
||||
* Get permissions for a specific role
|
||||
*/
|
||||
public function rolePermissions($roleId = null)
|
||||
{
|
||||
$role = $this->role->find($roleId);
|
||||
if (!$role) {
|
||||
return $this->error('Role not found', Response::HTTP_NOT_FOUND);
|
||||
}
|
||||
|
||||
$permissions = $this->rolePermission
|
||||
->where('role_id', $roleId)
|
||||
->findAll();
|
||||
|
||||
// Get all permissions with role permission data
|
||||
$allPermissions = $this->permission->findAll();
|
||||
$existingPermissions = [];
|
||||
|
||||
foreach ($permissions as $rolePermission) {
|
||||
$existingPermissions[$rolePermission['permission_id']] = [
|
||||
'can_create' => $rolePermission['can_create'],
|
||||
'can_read' => $rolePermission['can_read'],
|
||||
'can_update' => $rolePermission['can_update'],
|
||||
'can_delete' => $rolePermission['can_delete'],
|
||||
];
|
||||
}
|
||||
|
||||
return $this->success([
|
||||
'role' => $role,
|
||||
'permissions' => $allPermissions,
|
||||
'role_permissions' => $existingPermissions,
|
||||
], 'Role permissions retrieved successfully');
|
||||
}
|
||||
|
||||
/**
|
||||
* POST /api/v1/rolepermission/roles/{roleId}/permissions
|
||||
* Save role permissions
|
||||
*/
|
||||
public function saveRolePermissions($roleId = null)
|
||||
{
|
||||
$role = $this->role->find($roleId);
|
||||
if (!$role) {
|
||||
return $this->error('Role not found', Response::HTTP_NOT_FOUND);
|
||||
}
|
||||
|
||||
$payload = $this->payloadData();
|
||||
$permissions = $payload['permissions'] ?? null;
|
||||
|
||||
if (!$permissions || !is_array($permissions)) {
|
||||
return $this->respondError('Permissions data is required', Response::HTTP_BAD_REQUEST);
|
||||
}
|
||||
|
||||
// Fetch existing permissions for the role
|
||||
$rolePermissions = $this->rolePermission->where('role_id', $roleId)->findAll();
|
||||
$existingPermissions = [];
|
||||
|
||||
foreach ($rolePermissions as $rolePermission) {
|
||||
$existingPermissions[$rolePermission['permission_id']] = $rolePermission;
|
||||
}
|
||||
|
||||
try {
|
||||
DB::beginTransaction();
|
||||
|
||||
// Process the new permissions
|
||||
foreach ($permissions as $permissionId => $crudValues) {
|
||||
$permissionData = [
|
||||
'can_create' => isset($crudValues['create']) ? 1 : 0,
|
||||
'can_read' => isset($crudValues['read']) ? 1 : 0,
|
||||
'can_update' => isset($crudValues['update']) ? 1 : 0,
|
||||
'can_delete' => isset($crudValues['delete']) ? 1 : 0,
|
||||
'updated_at' => utc_now(),
|
||||
];
|
||||
|
||||
if (isset($existingPermissions[$permissionId])) {
|
||||
// Update existing permission
|
||||
$this->rolePermission->where('role_id', $roleId)
|
||||
->where('permission_id', $permissionId)
|
||||
->update($permissionData);
|
||||
} else {
|
||||
// Insert new permission
|
||||
$permissionData['role_id'] = $roleId;
|
||||
$permissionData['permission_id'] = $permissionId;
|
||||
$permissionData['created_at'] = utc_now();
|
||||
$this->rolePermission->insert($permissionData);
|
||||
}
|
||||
}
|
||||
|
||||
// Remove permissions that are no longer present
|
||||
foreach ($existingPermissions as $permissionId => $permissionData) {
|
||||
if (!isset($permissions[$permissionId])) {
|
||||
$this->rolePermission->where('role_id', $roleId)
|
||||
->where('permission_id', $permissionId)
|
||||
->delete();
|
||||
}
|
||||
}
|
||||
|
||||
DB::commit();
|
||||
|
||||
return $this->success(null, 'Permissions saved successfully');
|
||||
} catch (\Throwable $e) {
|
||||
DB::rollBack();
|
||||
log_message('error', 'Failed to save permissions: ' . $e->getMessage());
|
||||
return $this->respondError('Failed to save permissions: ' . $e->getMessage(), Response::HTTP_INTERNAL_SERVER_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* GET /api/v1/rolepermission/users
|
||||
* Get users with their roles
|
||||
*/
|
||||
public function users()
|
||||
{
|
||||
$users = $this->buildUsersWithRolesPayload();
|
||||
return $this->success($users, 'Users with roles retrieved successfully');
|
||||
}
|
||||
|
||||
/**
|
||||
* POST /api/v1/rolepermission/users/{userId}/roles
|
||||
* Assign roles to a user
|
||||
*/
|
||||
public function assignRole($userId = null)
|
||||
{
|
||||
$user = $this->user->find($userId);
|
||||
if (!$user) {
|
||||
return $this->error('User not found', Response::HTTP_NOT_FOUND);
|
||||
}
|
||||
|
||||
$payload = $this->payloadData();
|
||||
$roleIdsRaw = $payload['role_ids'] ?? [];
|
||||
|
||||
$roleIdsArray = is_array($roleIdsRaw) ? $roleIdsRaw : ($roleIdsRaw !== null ? [$roleIdsRaw] : []);
|
||||
$roleIds = array_values(array_unique(array_filter(array_map('intval', $roleIdsArray), fn($id) => $id > 0)));
|
||||
|
||||
$adminId = $this->getCurrentUserId();
|
||||
if (!$adminId) {
|
||||
return $this->respondError('Authentication required', Response::HTTP_UNAUTHORIZED);
|
||||
}
|
||||
|
||||
try {
|
||||
DB::beginTransaction();
|
||||
|
||||
// Remove all existing roles for the user
|
||||
$this->userRole->where('user_id', $userId)->delete();
|
||||
|
||||
// Assign new roles
|
||||
if (!empty($roleIds)) {
|
||||
foreach ($roleIds as $roleId) {
|
||||
$this->userRole->insert([
|
||||
'user_id' => $userId,
|
||||
'role_id' => $roleId,
|
||||
'created_at' => utc_now(),
|
||||
'updated_by' => $adminId
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
// Load role names after saving
|
||||
$assignedRoles = !empty($roleIds)
|
||||
? $this->role->whereIn('id', $roleIds)->findAll()
|
||||
: [];
|
||||
|
||||
$roleNames = array_map(fn($r) => strtolower($r['name']), $assignedRoles ?? []);
|
||||
|
||||
// Update staff record if needed
|
||||
$this->updateStaffRecord($userId, $roleNames);
|
||||
|
||||
DB::commit();
|
||||
|
||||
return $this->success(null, 'Roles updated successfully');
|
||||
} catch (\Throwable $e) {
|
||||
DB::rollBack();
|
||||
log_message('error', 'Error updating roles: ' . $e->getMessage());
|
||||
return $this->respondError('Failed to update roles: ' . $e->getMessage(), Response::HTTP_INTERNAL_SERVER_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* GET /api/v1/rolepermission/admins
|
||||
* Get admin users
|
||||
*/
|
||||
public function admins()
|
||||
{
|
||||
$admins = $this->user->newQuery()
|
||||
->select(['users.id', 'users.firstname', 'users.lastname', 'users.email'])
|
||||
->join('user_roles', 'user_roles.user_id', '=', 'users.id')
|
||||
->join('roles', 'roles.id', '=', 'user_roles.role_id')
|
||||
->where('roles.name', 'admin')
|
||||
->groupBy('users.id', 'users.firstname', 'users.lastname', 'users.email')
|
||||
->get()
|
||||
->toArray();
|
||||
|
||||
return $this->success($admins, 'Admin users retrieved successfully');
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper: Build users with roles payload
|
||||
*/
|
||||
private function buildUsersWithRolesPayload(): array
|
||||
{
|
||||
$rows = DB::table('users')
|
||||
->select('users.id', 'users.firstname', 'users.lastname', 'users.email', 'users.account_id', 'roles.name AS role_name')
|
||||
->leftJoin('user_roles', 'users.id', '=', 'user_roles.user_id')
|
||||
->leftJoin('roles', 'user_roles.role_id', '=', 'roles.id')
|
||||
->orderBy('users.id', 'ASC')
|
||||
->get()
|
||||
->toArray();
|
||||
|
||||
$users = [];
|
||||
|
||||
foreach ($rows as $row) {
|
||||
$row = (array) $row;
|
||||
if (!is_array($row)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$id = (int) ($row['id'] ?? 0);
|
||||
|
||||
if ($id <= 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!isset($users[$id])) {
|
||||
$users[$id] = [
|
||||
'id' => $id,
|
||||
'firstname' => $row['firstname'] ?? '',
|
||||
'lastname' => $row['lastname'] ?? '',
|
||||
'email' => $row['email'] ?? '',
|
||||
'account_id' => $row['account_id'] ?? '',
|
||||
'roles' => [],
|
||||
];
|
||||
}
|
||||
|
||||
$roleName = $row['role_name'] ?? null;
|
||||
if ($roleName) {
|
||||
$users[$id]['roles'][] = $roleName;
|
||||
}
|
||||
}
|
||||
|
||||
$normalized = array_map(static function ($user) {
|
||||
$roles = array_values(array_unique(array_filter($user['roles'] ?? [], 'strlen')));
|
||||
return [
|
||||
'id' => $user['id'],
|
||||
'firstname' => $user['firstname'] ?? '',
|
||||
'lastname' => $user['lastname'] ?? '',
|
||||
'email' => $user['email'] ?? '',
|
||||
'account_id' => $user['account_id'] ?? '',
|
||||
'roles' => $roles,
|
||||
];
|
||||
}, array_values($users));
|
||||
|
||||
return ['users' => $normalized];
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper: Update staff record based on roles
|
||||
*/
|
||||
private function updateStaffRecord(int $userId, array $newRoleNames): void
|
||||
{
|
||||
$excludedRoles = ['parent', 'student', 'guest'];
|
||||
|
||||
$loweredNewRoles = array_map('strtolower', $newRoleNames);
|
||||
|
||||
$user = $this->user->find($userId);
|
||||
if (!$user) {
|
||||
log_message('error', "updateStaffRecord: user_id {$userId} not found");
|
||||
return;
|
||||
}
|
||||
|
||||
// Fetch existing staff record if it exists
|
||||
$existingStaff = $this->staff->where('user_id', $userId)->first();
|
||||
|
||||
// Extract existing roles from DB if any
|
||||
$existingRoles = [];
|
||||
if (!empty($existingStaff['role_name'])) {
|
||||
$existingRoles = array_map('strtolower', array_map('trim', explode(',', $existingStaff['role_name'])));
|
||||
}
|
||||
|
||||
// Merge and deduplicate roles
|
||||
$allRoles = array_unique(array_merge($existingRoles, $loweredNewRoles));
|
||||
|
||||
// Determine staff roles (excluding parent/student/guest)
|
||||
$staffRoles = array_filter($newRoleNames, fn($role) => !in_array($role, $excludedRoles));
|
||||
|
||||
// Determine active role
|
||||
$activeRole = !empty($staffRoles) ? $staffRoles[0] : 'inactive';
|
||||
|
||||
$email = $this->generateUniqueStaffEmail($user['firstname'], $user['lastname'], $userId);
|
||||
|
||||
$now = utc_now();
|
||||
|
||||
$row = [
|
||||
'user_id' => $userId,
|
||||
'firstname' => $user['firstname'],
|
||||
'lastname' => $user['lastname'],
|
||||
'email' => $email,
|
||||
'phone' => $user['cellphone'] ?? null,
|
||||
'role_name' => implode(', ', $allRoles),
|
||||
'active_role' => $activeRole,
|
||||
'school_year' => $this->schoolYear,
|
||||
'updated_at' => $now,
|
||||
];
|
||||
|
||||
$this->staff->upsert($row);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper: Generate unique staff email
|
||||
*/
|
||||
private function generateUniqueStaffEmail(string $firstname, string $lastname, int $userId): string
|
||||
{
|
||||
$domain = '@alrahmaisgl.org';
|
||||
|
||||
// Sanitize names: lowercase, letters only
|
||||
$firstname = strtolower(preg_replace('/[^a-z]/i', '', $firstname));
|
||||
$lastname = strtolower(preg_replace('/[^a-z]/i', '', $lastname));
|
||||
|
||||
// Use at least 1 letter from firstname
|
||||
$min = 1;
|
||||
$max = strlen($firstname);
|
||||
$base = '';
|
||||
$email = '';
|
||||
|
||||
for ($i = $min; $i <= $max; $i++) {
|
||||
$base = substr($firstname, 0, $i) . $lastname;
|
||||
$email = $base . $domain;
|
||||
|
||||
// If email not taken or belongs to same user, use it
|
||||
$exists = $this->staff->where('email', $email)
|
||||
->where('user_id !=', $userId)
|
||||
->first();
|
||||
|
||||
if (!$exists) {
|
||||
return $email;
|
||||
}
|
||||
}
|
||||
|
||||
// If all combinations used, fallback to adding user ID
|
||||
return $base . $userId . $domain;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper: Ensure slug is unique
|
||||
*/
|
||||
private function ensureUniqueSlug(string $baseSlug, ?int $ignoreId = null): string
|
||||
{
|
||||
$slug = $baseSlug;
|
||||
$i = 2;
|
||||
|
||||
while (true) {
|
||||
$builder = $this->role->where('slug', $slug);
|
||||
if ($ignoreId !== null) {
|
||||
$builder->where('id !=', $ignoreId);
|
||||
}
|
||||
|
||||
$exists = $builder->countAllResults() > 0;
|
||||
|
||||
if (!$exists) {
|
||||
break;
|
||||
}
|
||||
|
||||
$slug = $baseSlug . '_' . $i;
|
||||
$i++;
|
||||
|
||||
if ($i > 100000) { // safety stop
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return $slug;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user