'taskUpdateDateAgeReference', 'enable_attendance_on' => 'taskEnableAttendanceOn', 'enable_attendance_off' => 'taskEnableAttendanceOff', 'set_semester_spring' => 'taskSetSemesterSpring', 'set_semester_fall' => 'taskSetSemesterFall', ]; public function availableTasks(): array { return array_keys($this->tasks); } public function runTask(string $task, bool $dry, bool $force, DateTimeZone $tz): array { if (! isset($this->tasks[$task])) { return ['ok' => false, 'message' => 'Unknown task.']; } $lockFile = storage_path('app/locks/config_update_'.$task.'.lock'); if (! is_dir(dirname($lockFile))) { @mkdir(dirname($lockFile), 0775, true); } $fp = @fopen($lockFile, 'c+'); if (! $fp) { return ['ok' => false, 'message' => 'Unable to open lock file.']; } if (! $force && ! flock($fp, LOCK_EX | LOCK_NB)) { fclose($fp); return ['ok' => false, 'message' => 'Task is already running.']; } try { $method = $this->tasks[$task]; $ok = (bool) $this->{$method}($dry, $force, $tz); return ['ok' => $ok, 'task' => $task]; } catch (\Throwable $e) { Log::error('ConfigUpdate task failed: '.$e->getMessage()); return ['ok' => false, 'message' => $e->getMessage()]; } finally { try { flock($fp, LOCK_UN); fclose($fp); @unlink($lockFile); } catch (\Throwable $e) { } } } private function taskEnableAttendanceOn(bool $dry, bool $force, DateTimeZone $tz): bool { return $this->setConfig('enable_attendance', '1', $dry); } private function taskEnableAttendanceOff(bool $dry, bool $force, DateTimeZone $tz): bool { return $this->setConfig('enable_attendance', '0', $dry); } private function taskUpdateDateAgeReference(bool $dry, bool $force, DateTimeZone $tz): bool { $now = new DateTimeImmutable('now', $tz); $isJune1 = $now->format('n-j') === '6-1'; if (! $isJune1 && ! $force) { return true; } $value = $now->format('Y').'-12-31'; return $dry ? true : Configuration::setConfigValueByKey('date_age_reference', $value); } private function taskSetSemesterSpring(bool $dry, bool $force, DateTimeZone $tz): bool { $now = new DateTimeImmutable('now', $tz); $isFeb1 = $now->format('n-j') === '2-1'; if (! $isFeb1 && ! $force) { return true; } return $dry ? true : Configuration::setConfigValueByKey('semester', 'Spring'); } private function taskSetSemesterFall(bool $dry, bool $force, DateTimeZone $tz): bool { $now = new DateTimeImmutable('now', $tz); $isJun1 = $now->format('n-j') === '6-1'; if (! $isJun1 && ! $force) { return true; } return $dry ? true : Configuration::setConfigValueByKey('semester', 'Fall'); } private function setConfig(string $key, string $value, bool $dry): bool { if ($dry) { return true; } return Configuration::setConfigValueByKey($key, $value); } }