diff --git a/.env.example b/.env.example index cbd1aa08..c3588b1b 100644 --- a/.env.example +++ b/.env.example @@ -99,6 +99,7 @@ FORCE_SCHEME= # Captcha settings # Available drivers: image, cloudflare_turnstile, google_recaptcha_v2 CAPTCHA_DRIVER=image +CAPTCHA_ATTENDANCE_ENABLED=true # Cloudflare Turnstile keys (used when CAPTCHA_DRIVER=cloudflare_turnstile) TURNSTILE_SITE_KEY= diff --git a/app/Filament/Resources/System/SettingResource/Pages/EditSetting.php b/app/Filament/Resources/System/SettingResource/Pages/EditSetting.php index 97ca00b6..9d3e3a31 100644 --- a/app/Filament/Resources/System/SettingResource/Pages/EditSetting.php +++ b/app/Filament/Resources/System/SettingResource/Pages/EditSetting.php @@ -13,6 +13,7 @@ use Filament\Forms\Components\TextInput; use Filament\Forms\Components\CheckboxList; use Filament\Schemas\Components\Fieldset; use Filament\Forms\Components\Repeater; +use Filament\Forms\Components\Toggle; use Filament\Schemas\Components\Utilities\Get; use Filament\Schemas\Components\Section; use App\Auth\Permission; @@ -30,6 +31,7 @@ use Filament\Facades\Filament; use Filament\Resources\Pages\Page; use Filament\Forms; use Illuminate\Support\HtmlString; +use Illuminate\Support\Arr; use Meilisearch\Contracts\Index\Settings; use Nexus\Database\NexusDB; @@ -64,6 +66,16 @@ class EditSetting extends Page implements HasForms private function fillForm() { $settings = Setting::getFromDb(); + + $fallbackEnabled = (bool) config('captcha.attendance.enabled', true); + $rawSetting = Arr::get($settings, 'captcha.attendance.enabled', $fallbackEnabled); + if (is_string($rawSetting)) { + $normalized = in_array(strtolower($rawSetting), ['1', 'true', 'yes'], true); + } else { + $normalized = (bool) $rawSetting; + } + Arr::set($settings, 'captcha.attendance.enabled', $normalized); + $this->form->fill($settings); } @@ -298,7 +310,20 @@ class EditSetting extends Page implements HasForms Setting::get('captcha.recaptcha.size', nexus_env('RECAPTCHA_SIZE', 'normal')) ); + $attendanceCaptchaSetting = Setting::get('captcha.attendance.enabled', true); + if (is_string($attendanceCaptchaSetting)) { + $attendanceCaptchaEnabled = in_array(strtolower($attendanceCaptchaSetting), ['1', 'true', 'yes'], true); + } else { + $attendanceCaptchaEnabled = (bool) $attendanceCaptchaSetting; + } + $schema = [ + Toggle::make("$captchaPrefix.attendance.enabled") + ->label(__('label.setting.captcha.attendance.enabled')) + ->helperText(__('label.setting.captcha.attendance.enabled_help')) + ->default($attendanceCaptchaEnabled) + ->columnSpanFull() + , Select::make("$captchaPrefix.default") ->options($driverOptions) ->label(__('label.setting.captcha.driver')) diff --git a/config/captcha.php b/config/captcha.php index 021a45ad..7cd90cc9 100644 --- a/config/captcha.php +++ b/config/captcha.php @@ -24,4 +24,8 @@ return [ 'size' => nexus_env('RECAPTCHA_SIZE', 'normal'), ], ], + + 'attendance' => [ + 'enabled' => nexus_env('CAPTCHA_ATTENDANCE_ENABLED', true), + ], ]; diff --git a/public/attendance.php b/public/attendance.php index dbb26f48..67b4325e 100644 --- a/public/attendance.php +++ b/public/attendance.php @@ -1,9 +1,14 @@ 'en-us', @@ -11,40 +16,52 @@ $localesMap = [ 'cht' => 'zh-tw', ]; $localeJs = $localesMap[$lang] ?? 'en-us'; - -\Nexus\Nexus::css('vendor/fullcalendar-5.10.2/main.min.css', 'header', true); -\Nexus\Nexus::js('vendor/fullcalendar-5.10.2/main.min.js', 'footer', true); \Nexus\Nexus::js("vendor/fullcalendar-5.10.2/locales/{$localeJs}.js", 'footer', true); -$rep = new \App\Repositories\AttendanceRepository(); - -if ($_SERVER['REQUEST_METHOD'] === 'POST') { - if ($iv == "yes") { - check_code($_POST['imagehash'] ?? null, $_POST['imagestring'] ?? null, 'attendance.php'); - } - $attendance = $rep->attend($CURUSER['id']); - if (!$attendance->is_updated) { - stderr($lang_attendance['sorry'], $lang_attendance['already_attended']); - } -} else { - $attendance = $rep->getAttendance($CURUSER['id']); - if (!$attendance) { - $attendance = new \App\Models\Attendance([ - 'uid' => $CURUSER['id'], - 'points' => 0, - 'days' => 0, - 'total_days' => 0, - ]); - $attendance->added = null; - } -} - $today = \Carbon\Carbon::today(); $tomorrow = \Carbon\Carbon::tomorrow(); $end = $today->clone()->endOfMonth(); $start = $today->clone()->subMonth(2); -$hasAttendedToday = $attendance->added && $attendance->added->isSameDay($today); +$attendanceRepository = new \App\Repositories\AttendanceRepository(); + +$attendanceCaptchaSetting = \App\Models\Setting::get('captcha.attendance.enabled', config('captcha.attendance.enabled', true)); +if (is_string($attendanceCaptchaSetting)) { + $attendanceCaptchaEnabled = in_array(strtolower($attendanceCaptchaSetting), ['1', 'true', 'yes'], true); +} else { + $attendanceCaptchaEnabled = (bool) $attendanceCaptchaSetting; +} + +if ($_SERVER['REQUEST_METHOD'] === 'POST') { + if ($attendanceCaptchaEnabled && $iv == 'yes') { + check_code($_POST['imagehash'] ?? null, $_POST['imagestring'] ?? null, 'attendance.php'); + } + $attendance = $attendanceRepository->attend($CURUSER['id']); + if (!$attendance->is_updated) { + stderr($lang_attendance['sorry'], $lang_attendance['already_attended']); + } +} else { + $attendance = $attendanceRepository->getAttendance($CURUSER['id']); +} + +$hasAttendedToday = $attendance && $attendance->added && $attendance->added->isSameDay($today); + +if (!$attendanceCaptchaEnabled && !$hasAttendedToday) { + $attendance = $attendanceRepository->attend($CURUSER['id']); + $hasAttendedToday = $attendance && $attendance->added && $attendance->added->isSameDay($today); +} + +if (!$attendance) { + $attendance = new \App\Models\Attendance([ + 'uid' => $CURUSER['id'], + 'points' => 0, + 'days' => 0, + 'total_days' => 0, + ]); + $attendance->added = null; + $hasAttendedToday = false; +} + stdhead($lang_attendance['title']); begin_main_frame(); @@ -74,6 +91,7 @@ if ($hasAttendedToday) { ->where('date', '>=', $start->format('Y-m-d')) ->get() ->keyBy('date'); + $interval = new \DateInterval('P1D'); $period = new \DatePeriod($start, $interval, $end); @@ -103,7 +121,7 @@ if ($hasAttendedToday) { $eventStr = json_encode($events); $validRangeStr = json_encode(['start' => $start->format('Y-m-d'), 'end' => $end->clone()->addDays(1)->format('Y-m-d')]); - $js = <<
'; echo '