strtolower(trim((string) $role)), array_filter($sessionRoles) ); return (bool) array_intersect($roles, ['administrator', 'administrative staff', 'principal', 'admin']); } public function isEmailUnique(string $email): bool { foreach (['users' => 'email', 'emergency_contacts' => 'email'] as $table => $column) { if ($this->db->table($table)->where($column, $email)->countAllResults() > 0) { return false; } } return true; } public function administratorParentList(): array { return $this->userModel->where('role', 'parent')->findAll(); } public function parentById(int $id): ?array { $parent = $this->userModel->find($id); return is_array($parent) ? $parent : null; } public function createAdministratorParent(array $post): bool|int|string { return $this->userModel->insert([ 'firstname' => $post['firstname'] ?? null, 'lastname' => $post['lastname'] ?? null, 'email' => strtolower((string) ($post['email'] ?? '')), 'password' => password_hash((string) ($post['password'] ?? ''), PASSWORD_DEFAULT), 'role' => 'parent', ]); } public function updateAdministratorParent(int $id, array $post): bool { $data = [ 'firstname' => $post['firstname'] ?? null, 'lastname' => $post['lastname'] ?? null, 'email' => strtolower((string) ($post['email'] ?? '')), ]; if (! empty($post['password'])) { $data['password'] = password_hash((string) $post['password'], PASSWORD_DEFAULT); } return (bool) $this->userModel->update($id, $data); } public function deleteParent(int $id): bool { return (bool) $this->userModel->delete($id); } public function createRelatedUser(array $userData, string $relationToStudent, string $semester, string $schoolYear): int|false { $schoolIdService = new SchoolIdService(); $token = bin2hex(random_bytes(48)); $tokenHash = hash('sha256', $token); $userType = in_array(strtolower($relationToStudent), ['wife', 'husband'], true) ? 'Secondary' : 'Tertiary'; $validation = \Config\Services::validation(); $validation->setRules([ 'firstname' => [ 'label' => 'First Name', 'rules' => 'required|min_length[2]|max_length[100]|regex_match[/^[A-Za-z\s\-]+$/]', 'errors' => ['regex_match' => 'First name may only contain letters, spaces, and dashes.'], ], 'lastname' => [ 'label' => 'Last Name', 'rules' => 'required|min_length[2]|max_length[100]|regex_match[/^[A-Za-z\s\-]+$/]', 'errors' => ['regex_match' => 'Last name may only contain letters, spaces, and dashes.'], ], 'email' => [ 'label' => 'Email Address', 'rules' => 'required|valid_email|max_length[150]|is_unique[users.email]', 'errors' => ['is_unique' => 'This email is already registered.'], ], 'cellphone' => [ 'label' => 'Cell Phone', 'rules' => 'required|regex_match[/^\d{10}$/]', 'errors' => ['regex_match' => 'Phone number must be exactly 10 digits.'], ], 'gender' => 'required|in_list[Male,Female]', 'city' => 'required|max_length[100]', 'state' => 'required|max_length[100]', 'zip' => 'required|regex_match[/^\d{5}$/]', ]); if (! $validation->run($userData)) { log_message('error', 'User creation failed due to invalid data: ' . json_encode($validation->getErrors())); return false; } $userEntry = [ 'firstname' => ucfirst(strtolower($userData['firstname'])), 'lastname' => ucfirst(strtolower($userData['lastname'])), 'gender' => $userData['gender'], 'cellphone' => $userData['cellphone'], 'email' => strtolower($userData['email']), 'address_street' => $userData['address_street'] ?? '', 'apt' => $userData['apt'] ?? null, 'city' => ucfirst(strtolower($userData['city'])), 'state' => strtoupper($userData['state']), 'zip' => $userData['zip'], 'accept_school_policy' => $userData['accept_school_policy'] ?? 0, 'token' => $tokenHash, 'is_verified' => 0, 'status' => 'Inactive', 'user_type' => $userType, 'semester' => $semester, 'school_year' => $schoolYear, 'school_id' => $schoolIdService->generateUserSchoolId(), ]; try { if (! $this->userModel->insert($userEntry)) { log_message('error', 'Failed to insert user: ' . print_r($this->userModel->errors(), true)); return false; } $userId = (int) $this->userModel->getInsertID(); $this->sendActivationEmail((string) $userData['email'], $token); log_message('info', "User with ID $userId created successfully and activation email sent."); return $userId; } catch (Exception $e) { log_message('error', 'Exception during user creation: ' . $e->getMessage()); return false; } } public function updateAuthorizedUsers(int $userId, array $data): void { $validation = \Config\Services::validation(); $validation->setRules([ 'email' => [ 'label' => 'Email', 'rules' => 'required|valid_email|max_length[150]', 'errors' => [ 'required' => 'Email is required.', 'valid_email' => 'Please provide a valid email address.', 'max_length' => 'Email must be less than 150 characters.', ], ], 'name' => [ 'label' => 'Name', 'rules' => 'required|min_length[3]|max_length[100]|regex_match[/^[A-Za-z\s\-]+$/]', 'errors' => [ 'required' => 'Name is required.', 'regex_match' => 'Name can only contain letters, spaces, and dashes.', 'min_length' => 'Name must be at least 3 characters long.', 'max_length' => 'Name must be less than 100 characters.', ], ], ]); if (! $validation->run($data)) { log_message('error', 'Invalid authorized user data: ' . json_encode($validation->getErrors())); return; } $existingAuthorizedUser = $this->authorizedUsersModel ->where('user_id', $userId) ->where('email', $data['email']) ->first(); if ($existingAuthorizedUser) { $this->authorizedUsersModel->update($existingAuthorizedUser['id'], $data); return; } $data['user_id'] = $userId; $data['status'] = 'Pending'; $this->authorizedUsersModel->insert($data); } private function sendActivationEmail(string $email, string $token): void { $emailController = new EmailController(); $subject = 'Activate Your Account'; $activationLink = site_url('/user/confirm/' . $token); $message = "Please click the following link to confirm your email and set your password: $activationLink"; if ($emailController->sendEmail($email, $subject, $message)) { log_message('info', 'Activation email sent successfully to ' . $email); } else { log_message('error', 'Failed to send activation email to ' . $email); } } }