From fb41caceffbaed591e5bd95485b0f2e082c506cf Mon Sep 17 00:00:00 2001 From: David Mosbach Date: Fri, 24 Nov 2023 15:56:34 +0000 Subject: [PATCH] Resolve "Crontab appQualificationCheckHour funktioniert nicht" --- config/settings.yml | 5 +- .../categories/qualification/de-de-formal.msg | 4 +- .../categories/qualification/en-eu.msg | 10 ++-- src/Handler/LMS.hs | 7 ++- src/Jobs/Crontab.hs | 25 ++++---- src/Settings.hs | 6 +- templates/i18n/lms-all/de-de-formal.hamlet | 57 +++++++++++++++++++ templates/i18n/lms-all/en-eu.hamlet | 57 +++++++++++++++++++ templates/lms-all.hamlet | 18 ------ 9 files changed, 144 insertions(+), 45 deletions(-) create mode 100644 templates/i18n/lms-all/de-de-formal.hamlet create mode 100644 templates/i18n/lms-all/en-eu.hamlet delete mode 100644 templates/lms-all.hamlet diff --git a/config/settings.yml b/config/settings.yml index ecc94093d..b3c228991 100644 --- a/config/settings.yml +++ b/config/settings.yml @@ -90,8 +90,9 @@ synchronise-avs-users-interval: "_env:SYNCHRONISE_AVS_INTERVAL:21600" # alle 6 study-features-recache-relevance-within: 172800 study-features-recache-relevance-interval: 293 -# Enqueue at specified hour, dequeue 30min later -# qualification-check-hour: 3 +# Enqueue at specified hour, a few minutes later +job-lms-qualifications-enqueue-hour: 15 +job-lms-qualifications-dequeue-hour: 3 log-settings: detailed: "_env:DETAILED_LOGGING:false" diff --git a/messages/uniworx/categories/qualification/de-de-formal.msg b/messages/uniworx/categories/qualification/de-de-formal.msg index 113121211..1571d7ac1 100644 --- a/messages/uniworx/categories/qualification/de-de-formal.msg +++ b/messages/uniworx/categories/qualification/de-de-formal.msg @@ -138,7 +138,5 @@ LmsNotificationSend n@Int: E‑Learning Benachrichtigungen an #{n} #{pluralDE n LmsPinRenewal n@Int: E‑Learning Passwort ausgetauscht für #{n} #{pluralDE n "Prüfling" "Prüflinge"}. LmsActionFailed n@Int: Aktion nicht durchgeführt für #{n} #{pluralDE n "Person" "Personen"}, da diese derzeit nicht an einer Prüfung teilnehmen. LmsStarted: E‑Learning eröffnet -LmsAutomaticQueuing n@Natural: Die folgenden Funktionen werden normalerweise einmal pro Tag um #{show n} Uhr ausgeführt. -LmsManualQueuing: Die folgenden Funktionen sollten einmal pro Tag ausgeführt werden. BtnLmsEnqueue: Nutzer mit ablaufenden Qualifikationen zum E‑Learning anmelden und benachrichtigen -BtnLmsDequeue: Nutzer mit beendetem E‑Learning ggf. benachrichtigen und aufräumen +BtnLmsDequeue: Nutzer mit beendetem E‑Learning aufräumen und ggf. benachrichtigen diff --git a/messages/uniworx/categories/qualification/en-eu.msg b/messages/uniworx/categories/qualification/en-eu.msg index 1cab2c3dd..5d466355b 100644 --- a/messages/uniworx/categories/qualification/en-eu.msg +++ b/messages/uniworx/categories/qualification/en-eu.msg @@ -7,7 +7,7 @@ QualificationName: Qualification QualificationDescription: Description QualificationValidIndicator: Validity QualificationValidDuration: Validity period -QualificationAuditDuration: Audit log keept +QualificationAuditDuration: Audit log retention period QualificationAuditDurationTooltip n@Int: Optional period for deletion of e‑learning data. Note that the e‑learning server may delete its anonymised data earlier, at most #{n} days after closing. QualificationRefreshWithin: Refresh within QualificationRefreshWithinTooltip: Optional period before expiry to start e‑learning and send a notification by post or email. @@ -19,7 +19,7 @@ QualificationExpiryNotificationTooltip: Qualification holder are notfied upon in TableQualificationCountActive: Active TableQualificationCountActiveTooltip: Number of currently valid qualification holders TableQualificationCountTotal: Total -TableQualificationIsAvsLicence: AVS Driving License +TableQualificationIsAvsLicence: AVS driving license TableQualificationIsAvsLicenceTooltip: Under which name is this qualification synchronized with AVS, if any? Only applies to qualification holders having an AVS PersonID. TableQualificationSapExport: Sent to SAP TableQualificationSapExportTooltip: Is this qualification transmitted to SAP? Only applies to qualification holder having a Fraport AG personnel number. @@ -138,7 +138,5 @@ LmsNotificationSend n: E‑learning notifications will be sent to #{n} #{pluralE LmsPinRenewal n: E‑learning password replaced randomly for #{n} #{pluralENs n "examinee"}. LmsActionFailed n: No action for #{n} #{pluralENs n "person"}, since there was no ongoing examination. LmsStarted: E‑learning open since -LmsAutomaticQueuing n@Natural: The following functions are executed daily at #{show n} o'clock. -LmsManualQueuing: The following functions should be executed daily. -BtnLmsEnqueue: Enqueue users with expiring qualifications for e‑learning and notify them. -BtnLmsDequeue: Dequeue users with finished e‑learning and notify, if appropriate. +BtnLmsEnqueue: Enqueue users with expiring qualifications for e‑learning and notify them +BtnLmsDequeue: Dequeue users with finished e‑learning and notify failed users diff --git a/src/Handler/LMS.hs b/src/Handler/LMS.hs index 682e0c7f4..2c4f6e437 100644 --- a/src/Handler/LMS.hs +++ b/src/Handler/LMS.hs @@ -75,7 +75,7 @@ embedRenderMessage ''UniWorX ''ButtonManualLms id instance Button UniWorX ButtonManualLms where btnClasses BtnLmsEnqueue = [BCIsButton, BCPrimary] - btnClasses BtnLmsDequeue = [BCIsButton, BCDefault] + btnClasses BtnLmsDequeue = [BCIsButton, BCPrimary] getLmsSchoolR :: SchoolId -> Handler Html @@ -85,7 +85,8 @@ getLmsAllR, postLmsAllR :: Handler Html getLmsAllR = postLmsAllR postLmsAllR = do isAdmin <- hasReadAccessTo AdminR - mbQcheck <- getsYesod $ view _appQualificationCheckHour + mbJLQenqueue <- getsYesod $ view _appJobLmsQualificationsEnqueueHour + mbJLQdequeue <- getsYesod $ view _appJobLmsQualificationsDequeueHour -- TODO: Move this functionality elsewhere without the need for `isAdmin` mbBtnForm <- if not isAdmin then return Nothing else do ((btnResult, btnWdgt), btnEnctype) <- runFormPost $ identifyForm ("buttons" :: Text) (buttonForm :: Form ButtonManualLms) @@ -109,7 +110,7 @@ postLmsAllR = do view _2 <$> mkLmsAllTable isAdmin lmsDeletionDays siteLayoutMsg MsgMenuLms $ do setTitleI MsgMenuLms - $(widgetFile "lms-all") + $(i18nWidgetFile "lms-all") type AllQualificationTableData = DBRow (Entity Qualification, Ex.Value Word64, Ex.Value Word64) resultAllQualification :: Lens' AllQualificationTableData Qualification diff --git a/src/Jobs/Crontab.hs b/src/Jobs/Crontab.hs index e352758ef..093c5cbde 100644 --- a/src/Jobs/Crontab.hs +++ b/src/Jobs/Crontab.hs @@ -1,4 +1,4 @@ --- SPDX-FileCopyrightText: 2022 Gregor Kleen ,Sarah Vaupel ,Sarah Vaupel ,Steffen Jost +-- SPDX-FileCopyrightText: 2022-2023 Sarah Vaupel , David Mosbach , Gregor Kleen ,Sarah Vaupel ,Sarah Vaupel ,Steffen Jost -- -- SPDX-License-Identifier: AGPL-3.0-or-later @@ -392,28 +392,31 @@ determineCrontab = execWriterT $ do -- , cronNotAfter = Right . CronTimestamp . utcToLocalTimeTZ appTZ $ addUTCTime appStudyFeaturesRecacheRelevanceInterval nextIntervalTime -- } - whenIsJust appQualificationCheckHour $ \hour -> tell $ HashMap.singleton + + whenIsJust appJobLmsQualificationsEnqueueHour $ \hour -> tell $ HashMap.singleton (JobCtlQueue JobLmsQualificationsEnqueue) Cron { cronInitial = CronAsap -- time after scheduling - , cronRepeat = CronRepeatScheduled $ cronCalendarAny { cronHour = cronMatchOne hour -- cronHour = CronMatchSome (impureNonNull $ Set.fromList [3,15] ) - , cronMinute = cronMatchOne 3 + , cronRepeat = CronRepeatScheduled $ cronCalendarAny { cronDayOfWeek = CronMatchSome . impureNonNull . Set.fromList $ [1..5] + , cronHour = cronMatchOne hour -- cronHour = CronMatchSome (impureNonNull $ Set.fromList [3,15] ) + , cronMinute = cronMatchOne 2 , cronSecond = cronMatchOne 27 } - , cronRateLimit = nominalDay / 2 -- minimal time between two executions, before the second job is skipped - , cronNotAfter = Left nominalDay -- maximal delay of an execution, before it is skipped entirely + , cronRateLimit = 600 -- minimal time between two executions, before the second job is skipped + , cronNotAfter = Right CronNotScheduled -- maximal delay of an execution, before it is skipped entirely } - whenIsJust appQualificationCheckHour $ \hour -> tell $ HashMap.singleton + whenIsJust appJobLmsQualificationsDequeueHour $ \hour -> tell $ HashMap.singleton (JobCtlQueue JobLmsQualificationsDequeue) Cron { cronInitial = CronAsap -- time after scheduling - , cronRepeat = CronRepeatScheduled $ cronCalendarAny { cronHour = cronMatchOne hour -- cronHour = CronMatchSome (impureNonNull $ Set.fromList [3,15] ) - , cronMinute = cronMatchOne 33 + , cronRepeat = CronRepeatScheduled $ cronCalendarAny { cronDayOfWeek = CronMatchSome . impureNonNull . Set.fromList $ [1..5] + , cronHour = cronMatchOne hour -- cronHour = CronMatchSome (impureNonNull $ Set.fromList [3,15] ) + , cronMinute = cronMatchOne 7 , cronSecond = cronMatchOne 27 } - , cronRateLimit = nominalDay / 2 -- minimal time between two executions, before the second job is skipped - , cronNotAfter = Left nominalDay -- maximal delay of an execution, before it is skipped entirely + , cronRateLimit = 600 -- minimal time between two executions, before the second job is skipped + , cronNotAfter = Right CronNotScheduled -- maximal delay of an execution, before it is skipped entirely } let diff --git a/src/Settings.hs b/src/Settings.hs index 0916f439f..e3fcc6105 100644 --- a/src/Settings.hs +++ b/src/Settings.hs @@ -233,7 +233,8 @@ data AppSettings = AppSettings , appStudyFeaturesRecacheRelevanceWithin :: Maybe NominalDiffTime , appStudyFeaturesRecacheRelevanceInterval :: NominalDiffTime - , appQualificationCheckHour :: Maybe Natural + , appJobLmsQualificationsEnqueueHour :: Maybe Natural + , appJobLmsQualificationsDequeueHour :: Maybe Natural , appFileSourceARCConf :: Maybe (ARCConf Int) , appFileSourcePrewarmConf :: Maybe PrewarmCacheConf @@ -785,7 +786,8 @@ instance FromJSON AppSettings where appStudyFeaturesRecacheRelevanceWithin <- o .:? "study-features-recache-relevance-within" appStudyFeaturesRecacheRelevanceInterval <- o .: "study-features-recache-relevance-interval" - appQualificationCheckHour <- o .:? "qualification-check-hour" + appJobLmsQualificationsEnqueueHour <- o .:? "job-lms-qualifications-enqueue-hour" + appJobLmsQualificationsDequeueHour <- o .:? "job-lms-qualifications-dequeue-hour" appFileSourceARCConf <- assertM isValidARCConf <$> o .:? "file-source-arc" diff --git a/templates/i18n/lms-all/de-de-formal.hamlet b/templates/i18n/lms-all/de-de-formal.hamlet new file mode 100644 index 000000000..c93ddfb58 --- /dev/null +++ b/templates/i18n/lms-all/de-de-formal.hamlet @@ -0,0 +1,57 @@ +$newline never + +$# SPDX-FileCopyrightText: 2022 Steffen Jost +$# +$# SPDX-License-Identifier: AGPL-3.0-or-later + +
+ ^{lmsTable} + +$maybe btnForm <- mbBtnForm +
+

+ E‑Learning Starten und Aufräumen +

+ Die folgenden Funktionen sollten normalerweise mindestens einmal pro Tag ausgeführt werden, # + können aber auch bedenkenlos mehrfach pro Tag ausgeführt werden. # + + Die erste Funktion benachrichtigt Inhaber von ablaufenden Lizenzen und # + lädt diese ggf. zum E‑Learning ein. # + + Die zweite Funktion benachrichtigt Inhaber von bereits abgelaufenen Lizenzen und # + räumte beendete E‑Learning Teilnehmer auf, falls der jeweilige Aufbewahrungszeitraum abgelaufen ist. # + + Ein Abgleich mit dem Ausweisverwaltungssystem findet dadurch jedoch noch nicht statt. # + +

+

+ Automatische Ausführung + +
+
+ Start E‑Learning: # +
+   + $maybe hour <- mbJLQenqueue + jeden Wochentag kurz nach # + + #{hour} Uhr + $nothing + + keine automatische Ausführung +
+ Sperren/Aufräumen: # +
+   + $maybe hour <- mbJLQdequeue + jeden Wochentag kurz nach # + + #{hour} Uhr + $nothing + + keine automatische Ausführung +

+

+ Manuelle Ausführung + + ^{btnForm} \ No newline at end of file diff --git a/templates/i18n/lms-all/en-eu.hamlet b/templates/i18n/lms-all/en-eu.hamlet new file mode 100644 index 000000000..69aa8df82 --- /dev/null +++ b/templates/i18n/lms-all/en-eu.hamlet @@ -0,0 +1,57 @@ +$newline never + +$# SPDX-FileCopyrightText: 2022 Steffen Jost +$# +$# SPDX-License-Identifier: AGPL-3.0-or-later + +
+ ^{lmsTable} + +$maybe btnForm <- mbBtnForm +
+

+ Starting and cleaning e‑learning +

+ The following functions should be executed at least once per day, # + but a repeated execution is harmless. # + + The first function notifies holders of expiring licences and # + enlists them for e‑learning, if appropriate for the respective qualification. # + + The second function notifies holders of already expired licences and # + cleans finished e‑learnings after their respective rentention periods. # + + Note that these functions do not trigger an AVS-synchronisation. # + +

+

+ Automatic execution + +
+
+ Start e‑learning: # +
+   + $maybe hour <- mbJLQenqueue + every weekday shortly after # + + #{hour} o'clock + $nothing + + no automatic execution +
+ Block/Clean: # +
+   + $maybe hour <- mbJLQdequeue + every weekday shortly after # + + #{hour} o'clock + $nothing + + no automatic execution +

+

+ Manual execution + + ^{btnForm} \ No newline at end of file diff --git a/templates/lms-all.hamlet b/templates/lms-all.hamlet deleted file mode 100644 index b4e5077fd..000000000 --- a/templates/lms-all.hamlet +++ /dev/null @@ -1,18 +0,0 @@ -$newline never - -$# SPDX-FileCopyrightText: 2022 Steffen Jost -$# -$# SPDX-License-Identifier: AGPL-3.0-or-later - -

- ^{lmsTable} - -$maybe btnForm <- mbBtnForm -

-

- $maybe qcheck <- mbQcheck - _{MsgLmsAutomaticQueuing qcheck} - $nothing - _{MsgLmsManualQueuing} -

- ^{btnForm} \ No newline at end of file