This commit is contained in:
@@ -2309,6 +2309,8 @@ class AdministratorController extends BaseController
|
||||
]);
|
||||
}
|
||||
|
||||
service('staffDirectorySync')->syncUser((int) $userId);
|
||||
|
||||
return redirect()->to('/administrator/manage-users');
|
||||
}
|
||||
|
||||
|
||||
@@ -72,13 +72,18 @@ class HomeworkTrackingController extends BaseController
|
||||
}
|
||||
|
||||
$limitToSemester = $this->hasTeacherAssignments($this->schoolYear, $this->semester);
|
||||
$semesterVariants = $this->getSemesterVariants($this->semester);
|
||||
|
||||
// Aggregate homework presence + first entered date per class_section_id + homework_index
|
||||
// Aggregate submitted homework per class_section_id + homework_index.
|
||||
// Adding a homework column creates blank rows for every student, so only
|
||||
// indexes with at least one non-null score count as submitted.
|
||||
$hwQ = $this->db->table('homework')
|
||||
->select('class_section_id, homework_index, MIN(created_at) AS first_created, COUNT(*) AS cnt')
|
||||
->select('class_section_id, homework_index')
|
||||
->select('MIN(CASE WHEN score IS NOT NULL THEN updated_at ELSE NULL END) AS first_submitted', false)
|
||||
->select('COUNT(score) AS scored_count', false)
|
||||
->where('school_year', $this->schoolYear);
|
||||
if ($limitToSemester && $this->semester !== '') {
|
||||
$hwQ->where('semester', $this->semester);
|
||||
if ($limitToSemester && $semesterVariants !== []) {
|
||||
$hwQ->whereIn('semester', $semesterVariants);
|
||||
}
|
||||
$rows = $hwQ->groupBy('class_section_id, homework_index')
|
||||
->get()
|
||||
@@ -90,60 +95,32 @@ class HomeworkTrackingController extends BaseController
|
||||
foreach ($rows as $r) {
|
||||
$csid = (int)($r['class_section_id'] ?? 0);
|
||||
$hi = (int)($r['homework_index'] ?? 0);
|
||||
$cnt = (int)($r['cnt'] ?? 0);
|
||||
$cnt = (int)($r['scored_count'] ?? 0);
|
||||
if ($csid > 0 && $hi > 0 && $cnt > 0) {
|
||||
$hasHomework[$csid][$hi] = true;
|
||||
$dateStr = substr((string)($r['first_created'] ?? ''), 0, 10);
|
||||
$dateStr = substr((string)($r['first_submitted'] ?? ''), 0, 10);
|
||||
$hwEnteredAt[$csid][$hi] = $dateStr ?: null;
|
||||
$homeworkSubmissionCounts[$csid] = ($homeworkSubmissionCounts[$csid] ?? 0) + 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Build date-based presence mapped to the nearest prior non-NoSchool Sunday.
|
||||
$hb = $this->db->table('homework')
|
||||
->select("class_section_id, DATE(created_at) AS hw_date, MIN(created_at) AS first_created, COUNT(*) AS cnt", false)
|
||||
->where('school_year', $this->schoolYear);
|
||||
if ($limitToSemester && $this->semester !== '') {
|
||||
$hb->where('semester', $this->semester);
|
||||
$indexToDate = [];
|
||||
foreach ($dateToIndex as $ymd => $homeworkIndex) {
|
||||
if ($homeworkIndex !== null) {
|
||||
$indexToDate[(int) $homeworkIndex] = $ymd;
|
||||
}
|
||||
}
|
||||
$rowsByDate = $hb->groupBy('class_section_id, DATE(created_at)', '', false)
|
||||
->orderBy('hw_date', 'ASC', false)
|
||||
->get()
|
||||
->getResultArray();
|
||||
|
||||
$hasHomeworkByDate = [];
|
||||
$hwEnteredAtByDate = [];
|
||||
foreach ($rowsByDate as $r) {
|
||||
$csid = (int)($r['class_section_id'] ?? 0);
|
||||
$d = substr((string)($r['hw_date'] ?? ''), 0, 10);
|
||||
$cnt = (int)($r['cnt'] ?? 0);
|
||||
$firstCreated = substr((string)($r['first_created'] ?? ''), 0, 10);
|
||||
if ($csid <= 0 || !$d || $cnt <= 0) { continue; }
|
||||
|
||||
// Find the index of the last Sunday on or before $d
|
||||
$baseIndex = -1;
|
||||
for ($i = count($sundays) - 1; $i >= 0; $i--) {
|
||||
if ($sundays[$i] <= $d) { $baseIndex = $i; break; }
|
||||
}
|
||||
if ($baseIndex < 0) { continue; }
|
||||
|
||||
// Map this homework day to only the nearest prior non–No School Sunday
|
||||
$j = $baseIndex;
|
||||
while ($j >= 0 && !empty($eventDays[$sundays[$j]])) { $j--; }
|
||||
if ($j < 0) { continue; }
|
||||
$sd = $sundays[$j];
|
||||
|
||||
// Mark homework on that Sunday for this class_section (single mapping)
|
||||
$hasHomeworkByDate[$csid][$sd] = true;
|
||||
if (empty($hwEnteredAtByDate[$csid][$sd])) {
|
||||
$hwEnteredAtByDate[$csid][$sd] = $firstCreated ?: $d;
|
||||
} else {
|
||||
// Keep the earliest date for display
|
||||
$existing = (string)$hwEnteredAtByDate[$csid][$sd];
|
||||
$candidate = $firstCreated ?: $d;
|
||||
if ($candidate && (!$existing || $candidate < $existing)) {
|
||||
$hwEnteredAtByDate[$csid][$sd] = $candidate;
|
||||
foreach ($hasHomework as $csid => $indexes) {
|
||||
foreach ($indexes as $homeworkIndex => $_submitted) {
|
||||
$ymd = $indexToDate[(int) $homeworkIndex] ?? null;
|
||||
if ($ymd === null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$hasHomeworkByDate[(int) $csid][$ymd] = true;
|
||||
$hwEnteredAtByDate[(int) $csid][$ymd] = $hwEnteredAt[(int) $csid][(int) $homeworkIndex] ?? null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -252,6 +229,21 @@ class HomeworkTrackingController extends BaseController
|
||||
return $this->teacherAssignmentCache[$year];
|
||||
}
|
||||
|
||||
private function getSemesterVariants(string $semester): array
|
||||
{
|
||||
$trimmed = trim($semester);
|
||||
if ($trimmed === '') {
|
||||
return [];
|
||||
}
|
||||
|
||||
return array_values(array_unique([
|
||||
$trimmed,
|
||||
ucfirst(strtolower($trimmed)),
|
||||
strtolower($trimmed),
|
||||
strtoupper($trimmed),
|
||||
]));
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute start/end dates for the given semester within the school year.
|
||||
* Fall: 09/21/{startYear} to 01/18/{startYear+1}
|
||||
|
||||
@@ -9,6 +9,7 @@ use App\Models\UserModel;
|
||||
use App\Models\UserRoleModel;
|
||||
use App\Models\ConfigurationModel;
|
||||
use App\Models\StaffModel;
|
||||
use App\Services\StaffDirectorySyncService;
|
||||
use CodeIgniter\Controller;
|
||||
|
||||
class RolePermissionController extends Controller
|
||||
@@ -20,6 +21,7 @@ class RolePermissionController extends Controller
|
||||
protected $configModel;
|
||||
protected $permissionModel;
|
||||
protected $rolePermissionModel;
|
||||
protected StaffDirectorySyncService $staffDirectorySync;
|
||||
protected $request;
|
||||
protected $db;
|
||||
protected $schoolYear;
|
||||
@@ -31,6 +33,7 @@ class RolePermissionController extends Controller
|
||||
$this->userModel = new UserModel();
|
||||
$this->userRoleModel = new UserRoleModel();
|
||||
$this->staffModel = new StaffModel();
|
||||
$this->staffDirectorySync = service('staffDirectorySync');
|
||||
$this->configModel = new ConfigurationModel();
|
||||
$this->permissionModel = new PermissionModel();
|
||||
$this->rolePermissionModel = new RolePermissionModel();
|
||||
@@ -224,49 +227,7 @@ class RolePermissionController extends Controller
|
||||
|
||||
private function updateStaffRecord(int $userId, array $newRoleNames): void
|
||||
{
|
||||
$excludedRoles = ['parent', 'student', 'guest'];
|
||||
$loweredNewRoles = array_map('strtolower', $newRoleNames);
|
||||
|
||||
$user = $this->userModel->find($userId);
|
||||
if (!$user) {
|
||||
log_message('error', "updateStaffRecord: user_id {$userId} not found");
|
||||
return;
|
||||
}
|
||||
|
||||
// Fetch existing staff record if it exists
|
||||
$existingStaff = $this->staffModel->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'],
|
||||
'role_name' => implode(', ', $allRoles), // historical roles
|
||||
'active_role' => $activeRole,
|
||||
'school_year' => $this->schoolYear,
|
||||
'updated_at' => $now,
|
||||
];
|
||||
|
||||
$this->staffModel->upsert($row);
|
||||
$this->staffDirectorySync->syncUser($userId);
|
||||
}
|
||||
|
||||
private function generateUniqueStaffEmail(string $firstname, string $lastname, int $userId): string
|
||||
|
||||
@@ -7,6 +7,7 @@ use App\Models\StaffModel;
|
||||
use App\Models\UserModel;
|
||||
use App\Models\TeacherClassModel;
|
||||
use App\Models\ConfigurationModel;
|
||||
use App\Services\StaffDirectorySyncService;
|
||||
|
||||
class StaffController extends BaseController
|
||||
{
|
||||
@@ -16,6 +17,7 @@ class StaffController extends BaseController
|
||||
protected $teacherClassModel;
|
||||
protected $userModel;
|
||||
protected $staffModel;
|
||||
protected StaffDirectorySyncService $staffDirectorySync;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
@@ -24,6 +26,7 @@ class StaffController extends BaseController
|
||||
$this->teacherClassModel = new TeacherClassModel();
|
||||
$this->userModel = new UserModel();
|
||||
$this->staffModel = new StaffModel();
|
||||
$this->staffDirectorySync = service('staffDirectorySync');
|
||||
|
||||
// Retrieve the configuration values
|
||||
$this->semester = $this->configModel->getConfig('semester');
|
||||
@@ -38,61 +41,11 @@ class StaffController extends BaseController
|
||||
|
||||
$schoolYear = $this->currentSchoolYearName((string) ($this->schoolYear ?? ''));
|
||||
|
||||
// roles we never show
|
||||
$excludedRoles = ['student', 'parent', 'guest', 'inactive']; // ← add inactive here
|
||||
|
||||
$staffList = $this->staffModel
|
||||
->whereNotIn('LOWER(active_role)', array_map('strtolower', $excludedRoles))
|
||||
->orderBy('created_at', 'DESC')
|
||||
->findAll();
|
||||
|
||||
// Preload assignments for the selected school year (across all semesters),
|
||||
// mirroring the logic used in teacher_class_assignment.
|
||||
$assignRows = $this->teacherClassModel
|
||||
->select('teacher_class.teacher_id, teacher_class.position, classSection.class_section_name')
|
||||
->join('classSection', 'classSection.class_section_id = teacher_class.class_section_id', 'left')
|
||||
->where('teacher_class.school_year', $schoolYear)
|
||||
->findAll();
|
||||
|
||||
$assignByTeacher = [];
|
||||
foreach ($assignRows as $r) {
|
||||
$tid = (int)($r['teacher_id'] ?? 0);
|
||||
if ($tid <= 0) { continue; }
|
||||
$name = trim((string)($r['class_section_name'] ?? ''));
|
||||
if ($name === '') { continue; }
|
||||
$pos = strtolower((string)($r['position'] ?? ''));
|
||||
if (!in_array($pos, ['main','ta'], true)) { continue; }
|
||||
$assignByTeacher[$tid][] = $name . ' (' . $pos . ')';
|
||||
}
|
||||
|
||||
$issuesCount = 0;
|
||||
foreach ($staffList as &$staff) {
|
||||
// attach school_id
|
||||
$staff['school_id'] = $this->userModel->getSchoolIdByUserId($staff['user_id'] ?? null);
|
||||
|
||||
// Verify and attach class assignments for teacher/TA roles for the selected school year
|
||||
$role = strtolower((string)($staff['active_role'] ?? ''));
|
||||
if (in_array($role, ['teacher', 'teacher_assistant'], true)) {
|
||||
$tid = (int)($staff['user_id'] ?? 0);
|
||||
$labels = $assignByTeacher[$tid] ?? [];
|
||||
if (!empty($labels)) {
|
||||
$staff['class_section'] = implode(', ', array_unique($labels));
|
||||
$staff['verification_issue'] = false;
|
||||
} else {
|
||||
$staff['class_section'] = 'No class assigned';
|
||||
$staff['verification_issue'] = true;
|
||||
$issuesCount++;
|
||||
}
|
||||
} else {
|
||||
$staff['class_section'] = '—';
|
||||
$staff['verification_issue'] = false;
|
||||
}
|
||||
}
|
||||
unset($staff); // break reference
|
||||
$directory = $this->staffDirectorySync->activeStaffForSchoolYear($schoolYear);
|
||||
|
||||
return view('staff/index', [
|
||||
'staff' => $staffList,
|
||||
'issues_count' => $issuesCount,
|
||||
'staff' => $directory['staff'],
|
||||
'issues_count' => $directory['issues_count'],
|
||||
'semester' => $this->semester,
|
||||
'school_year' => $schoolYear,
|
||||
]);
|
||||
|
||||
@@ -15,6 +15,7 @@ use App\Models\IpAttemptModel;
|
||||
use CodeIgniter\Controller;
|
||||
use App\Controllers\View\EmailController;
|
||||
use App\Models\LoginActivityModel; // Make sure this import is present
|
||||
use App\Services\StaffDirectorySyncService;
|
||||
require_once APPPATH . 'Helpers/pbkdf2_helper.php';
|
||||
|
||||
|
||||
@@ -29,6 +30,7 @@ class UserController extends BaseController
|
||||
protected $passwordResetModel;
|
||||
protected $loginActivityModel;
|
||||
protected $resetRequestModel;
|
||||
protected StaffDirectorySyncService $staffDirectorySync;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
@@ -48,6 +50,7 @@ class UserController extends BaseController
|
||||
$this->passwordResetModel = new PasswordResetModel();
|
||||
$this->loginActivityModel = new LoginActivityModel();
|
||||
$this->resetRequestModel = new PasswordResetRequestModel();
|
||||
$this->staffDirectorySync = service('staffDirectorySync');
|
||||
}
|
||||
|
||||
private function denyAccess(string $message)
|
||||
@@ -382,6 +385,8 @@ class UserController extends BaseController
|
||||
return redirect()->back()->withInput()->with('errors', $this->userRoleModel->errors());
|
||||
}
|
||||
|
||||
$this->staffDirectorySync->syncUser((int) $userId);
|
||||
|
||||
return redirect()->to('/user');
|
||||
}
|
||||
|
||||
@@ -412,6 +417,7 @@ class UserController extends BaseController
|
||||
|
||||
// Delete the user's roles from the user_roles table
|
||||
$this->userRoleModel->where('user_id', $id)->delete();
|
||||
$this->staffDirectorySync->syncUser((int) $id);
|
||||
|
||||
return redirect()->to('/user');
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user