chore(lms): split qualification-check-hour into two
This commit is contained in:
parent
9c047ae749
commit
e723dd9b17
@ -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-within: 172800
|
||||||
study-features-recache-relevance-interval: 293
|
study-features-recache-relevance-interval: 293
|
||||||
|
|
||||||
# Enqueue at specified hour, dequeue 30min later
|
# Enqueue at specified hour, a few minutes later
|
||||||
qualification-check-hour: 3
|
job-lms-qualifications-enqueue-hour: 15
|
||||||
|
job-lms-qualifications-dequeue-hour: 3
|
||||||
|
|
||||||
log-settings:
|
log-settings:
|
||||||
detailed: "_env:DETAILED_LOGGING:false"
|
detailed: "_env:DETAILED_LOGGING:false"
|
||||||
|
|||||||
@ -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"}.
|
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.
|
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
|
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
|
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
|
||||||
|
|||||||
@ -7,7 +7,7 @@ QualificationName: Qualification
|
|||||||
QualificationDescription: Description
|
QualificationDescription: Description
|
||||||
QualificationValidIndicator: Validity
|
QualificationValidIndicator: Validity
|
||||||
QualificationValidDuration: Validity period
|
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.
|
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
|
QualificationRefreshWithin: Refresh within
|
||||||
QualificationRefreshWithinTooltip: Optional period before expiry to start e‑learning and send a notification by post or email.
|
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
|
TableQualificationCountActive: Active
|
||||||
TableQualificationCountActiveTooltip: Number of currently valid qualification holders
|
TableQualificationCountActiveTooltip: Number of currently valid qualification holders
|
||||||
TableQualificationCountTotal: Total
|
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.
|
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
|
TableQualificationSapExport: Sent to SAP
|
||||||
TableQualificationSapExportTooltip: Is this qualification transmitted to SAP? Only applies to qualification holder having a Fraport AG personnel number.
|
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"}.
|
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.
|
LmsActionFailed n: No action for #{n} #{pluralENs n "person"}, since there was no ongoing examination.
|
||||||
LmsStarted: E‑learning open since
|
LmsStarted: E‑learning open since
|
||||||
LmsAutomaticQueuing n@Natural: The following functions are executed daily at #{show n} o'clock.
|
BtnLmsEnqueue: Enqueue users with expiring qualifications for e‑learning and notify them
|
||||||
LmsManualQueuing: The following functions should be executed daily.
|
BtnLmsDequeue: Dequeue users with finished e‑learning and notify failed users
|
||||||
BtnLmsEnqueue: Enqueue users with expiring qualifications for e‑learning and notify them.
|
|
||||||
BtnLmsDequeue: Dequeue users with finished e‑learning and notify, if appropriate.
|
|
||||||
|
|||||||
@ -76,7 +76,7 @@ embedRenderMessage ''UniWorX ''ButtonManualLms id
|
|||||||
|
|
||||||
instance Button UniWorX ButtonManualLms where
|
instance Button UniWorX ButtonManualLms where
|
||||||
btnClasses BtnLmsEnqueue = [BCIsButton, BCPrimary]
|
btnClasses BtnLmsEnqueue = [BCIsButton, BCPrimary]
|
||||||
btnClasses BtnLmsDequeue = [BCIsButton, BCDefault]
|
btnClasses BtnLmsDequeue = [BCIsButton, BCPrimary]
|
||||||
|
|
||||||
|
|
||||||
getLmsSchoolR :: SchoolId -> Handler Html
|
getLmsSchoolR :: SchoolId -> Handler Html
|
||||||
@ -86,7 +86,8 @@ getLmsAllR, postLmsAllR :: Handler Html
|
|||||||
getLmsAllR = postLmsAllR
|
getLmsAllR = postLmsAllR
|
||||||
postLmsAllR = do
|
postLmsAllR = do
|
||||||
isAdmin <- hasReadAccessTo AdminR
|
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`
|
-- TODO: Move this functionality elsewhere without the need for `isAdmin`
|
||||||
mbBtnForm <- if not isAdmin then return Nothing else do
|
mbBtnForm <- if not isAdmin then return Nothing else do
|
||||||
((btnResult, btnWdgt), btnEnctype) <- runFormPost $ identifyForm ("buttons" :: Text) (buttonForm :: Form ButtonManualLms)
|
((btnResult, btnWdgt), btnEnctype) <- runFormPost $ identifyForm ("buttons" :: Text) (buttonForm :: Form ButtonManualLms)
|
||||||
@ -110,7 +111,7 @@ postLmsAllR = do
|
|||||||
view _2 <$> mkLmsAllTable isAdmin lmsDeletionDays
|
view _2 <$> mkLmsAllTable isAdmin lmsDeletionDays
|
||||||
siteLayoutMsg MsgMenuLms $ do
|
siteLayoutMsg MsgMenuLms $ do
|
||||||
setTitleI MsgMenuLms
|
setTitleI MsgMenuLms
|
||||||
$(widgetFile "lms-all")
|
$(i18nWidgetFile "lms-all")
|
||||||
|
|
||||||
type AllQualificationTableData = DBRow (Entity Qualification, Ex.Value Word64, Ex.Value Word64)
|
type AllQualificationTableData = DBRow (Entity Qualification, Ex.Value Word64, Ex.Value Word64)
|
||||||
resultAllQualification :: Lens' AllQualificationTableData Qualification
|
resultAllQualification :: Lens' AllQualificationTableData Qualification
|
||||||
|
|||||||
@ -393,26 +393,26 @@ determineCrontab = execWriterT $ do
|
|||||||
-- }
|
-- }
|
||||||
|
|
||||||
|
|
||||||
whenIsJust appQualificationCheckHour $ \hour -> tell $ HashMap.singleton
|
whenIsJust appJobLmsQualificationsEnqeueHour $ \hour -> tell $ HashMap.singleton
|
||||||
(JobCtlQueue JobLmsQualificationsEnqueue)
|
(JobCtlQueue JobLmsQualificationsEnqueue)
|
||||||
Cron
|
Cron
|
||||||
{ cronInitial = CronAsap -- time after scheduling
|
{ cronInitial = CronAsap -- time after scheduling
|
||||||
, cronRepeat = CronRepeatScheduled $ cronCalendarAny { cronDayOfWeek = CronMatchSome . impureNonNull . Set.fromList $ [1..5]
|
, cronRepeat = CronRepeatScheduled $ cronCalendarAny { cronDayOfWeek = CronMatchSome . impureNonNull . Set.fromList $ [1..5]
|
||||||
, cronHour = cronMatchOne hour -- cronHour = CronMatchSome (impureNonNull $ Set.fromList [3,15] )
|
, cronHour = cronMatchOne hour -- cronHour = CronMatchSome (impureNonNull $ Set.fromList [3,15] )
|
||||||
, cronMinute = cronMatchOne 3
|
, cronMinute = cronMatchOne 2
|
||||||
, cronSecond = cronMatchOne 27
|
, cronSecond = cronMatchOne 27
|
||||||
}
|
}
|
||||||
, cronRateLimit = 600 -- minimal time between two executions, before the second job is skipped
|
, 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
|
, 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)
|
(JobCtlQueue JobLmsQualificationsDequeue)
|
||||||
Cron
|
Cron
|
||||||
{ cronInitial = CronAsap -- time after scheduling
|
{ cronInitial = CronAsap -- time after scheduling
|
||||||
, cronRepeat = CronRepeatScheduled $ cronCalendarAny { cronDayOfWeek = CronMatchSome . impureNonNull . Set.fromList $ [1..5]
|
, cronRepeat = CronRepeatScheduled $ cronCalendarAny { cronDayOfWeek = CronMatchSome . impureNonNull . Set.fromList $ [1..5]
|
||||||
, cronHour = cronMatchOne hour -- cronHour = CronMatchSome (impureNonNull $ Set.fromList [3,15] )
|
, cronHour = cronMatchOne hour -- cronHour = CronMatchSome (impureNonNull $ Set.fromList [3,15] )
|
||||||
, cronMinute = cronMatchOne 33
|
, cronMinute = cronMatchOne 7
|
||||||
, cronSecond = cronMatchOne 27
|
, cronSecond = cronMatchOne 27
|
||||||
}
|
}
|
||||||
, cronRateLimit = 600 -- minimal time between two executions, before the second job is skipped
|
, cronRateLimit = 600 -- minimal time between two executions, before the second job is skipped
|
||||||
|
|||||||
@ -233,7 +233,8 @@ data AppSettings = AppSettings
|
|||||||
, appStudyFeaturesRecacheRelevanceWithin :: Maybe NominalDiffTime
|
, appStudyFeaturesRecacheRelevanceWithin :: Maybe NominalDiffTime
|
||||||
, appStudyFeaturesRecacheRelevanceInterval :: NominalDiffTime
|
, appStudyFeaturesRecacheRelevanceInterval :: NominalDiffTime
|
||||||
|
|
||||||
, appQualificationCheckHour :: Maybe Natural
|
, appJobLmsQualificationsEnqueueHour :: Maybe Natural
|
||||||
|
, appJobLmsQualificationsDequeueHour :: Maybe Natural
|
||||||
|
|
||||||
, appFileSourceARCConf :: Maybe (ARCConf Int)
|
, appFileSourceARCConf :: Maybe (ARCConf Int)
|
||||||
, appFileSourcePrewarmConf :: Maybe PrewarmCacheConf
|
, appFileSourcePrewarmConf :: Maybe PrewarmCacheConf
|
||||||
@ -784,7 +785,8 @@ instance FromJSON AppSettings where
|
|||||||
appStudyFeaturesRecacheRelevanceWithin <- o .:? "study-features-recache-relevance-within"
|
appStudyFeaturesRecacheRelevanceWithin <- o .:? "study-features-recache-relevance-within"
|
||||||
appStudyFeaturesRecacheRelevanceInterval <- o .: "study-features-recache-relevance-interval"
|
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"
|
appFileSourceARCConf <- assertM isValidARCConf <$> o .:? "file-source-arc"
|
||||||
|
|
||||||
|
|||||||
57
templates/i18n/lms-all/de-de-formal.hamlet
Normal file
57
templates/i18n/lms-all/de-de-formal.hamlet
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
$newline never
|
||||||
|
|
||||||
|
$# SPDX-FileCopyrightText: 2022 Steffen Jost <jost@tcs.ifi.lmu.de>
|
||||||
|
$#
|
||||||
|
$# SPDX-License-Identifier: AGPL-3.0-or-later
|
||||||
|
|
||||||
|
<section>
|
||||||
|
^{lmsTable}
|
||||||
|
|
||||||
|
$maybe btnForm <- mbBtnForm
|
||||||
|
<section>
|
||||||
|
<h3>
|
||||||
|
E‑Learning Starten und Aufräumen
|
||||||
|
<p>
|
||||||
|
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. #
|
||||||
|
|
||||||
|
<p>
|
||||||
|
<h4>
|
||||||
|
Automatische Ausführung
|
||||||
|
|
||||||
|
<dl .deflist>
|
||||||
|
<dt .deflist_dt>
|
||||||
|
Start E‑Learning: #
|
||||||
|
<dd .deflist_dd>
|
||||||
|
|
||||||
|
$maybe hour <- mbJLQenqueue
|
||||||
|
jeden Wochentag kurz nach #
|
||||||
|
<b>
|
||||||
|
#{hour} Uhr
|
||||||
|
$nothing
|
||||||
|
<em>
|
||||||
|
keine automatische Ausführung
|
||||||
|
<dt .deflist_dt>
|
||||||
|
Sperren/Aufräumen: #
|
||||||
|
<dd .deflist_dd>
|
||||||
|
|
||||||
|
$maybe hour <- mbJLQdequeue
|
||||||
|
jeden Wochentag kurz nach #
|
||||||
|
<b>
|
||||||
|
#{hour} Uhr
|
||||||
|
$nothing
|
||||||
|
<em>
|
||||||
|
keine automatische Ausführung
|
||||||
|
<p>
|
||||||
|
<h4>
|
||||||
|
Manuelle Ausführung
|
||||||
|
|
||||||
|
^{btnForm}
|
||||||
57
templates/i18n/lms-all/en-eu.hamlet
Normal file
57
templates/i18n/lms-all/en-eu.hamlet
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
$newline never
|
||||||
|
|
||||||
|
$# SPDX-FileCopyrightText: 2022 Steffen Jost <jost@tcs.ifi.lmu.de>
|
||||||
|
$#
|
||||||
|
$# SPDX-License-Identifier: AGPL-3.0-or-later
|
||||||
|
|
||||||
|
<section>
|
||||||
|
^{lmsTable}
|
||||||
|
|
||||||
|
$maybe btnForm <- mbBtnForm
|
||||||
|
<section>
|
||||||
|
<h3>
|
||||||
|
Starting and cleaning e‑learning
|
||||||
|
<p>
|
||||||
|
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. #
|
||||||
|
|
||||||
|
<p>
|
||||||
|
<h4>
|
||||||
|
Automatic execution
|
||||||
|
|
||||||
|
<dl .deflist>
|
||||||
|
<dt .deflist_dt>
|
||||||
|
Start e‑learning: #
|
||||||
|
<dd .deflist_dd>
|
||||||
|
|
||||||
|
$maybe hour <- mbJLQenqueue
|
||||||
|
every weekday shortly after #
|
||||||
|
<b>
|
||||||
|
#{hour} o'clock
|
||||||
|
$nothing
|
||||||
|
<em>
|
||||||
|
no automatic execution
|
||||||
|
<dt .deflist_dt>
|
||||||
|
Block/Clean: #
|
||||||
|
<dd .deflist_dd>
|
||||||
|
|
||||||
|
$maybe hour <- mbJLQdequeue
|
||||||
|
every weekday shortly after #
|
||||||
|
<b>
|
||||||
|
#{hour} o'clock
|
||||||
|
$nothing
|
||||||
|
<em>
|
||||||
|
no automatic execution
|
||||||
|
<p>
|
||||||
|
<h4>
|
||||||
|
Manual execution
|
||||||
|
|
||||||
|
^{btnForm}
|
||||||
@ -1,18 +0,0 @@
|
|||||||
$newline never
|
|
||||||
|
|
||||||
$# SPDX-FileCopyrightText: 2022 Steffen Jost <jost@tcs.ifi.lmu.de>
|
|
||||||
$#
|
|
||||||
$# SPDX-License-Identifier: AGPL-3.0-or-later
|
|
||||||
|
|
||||||
<p>
|
|
||||||
^{lmsTable}
|
|
||||||
|
|
||||||
$maybe btnForm <- mbBtnForm
|
|
||||||
<section>
|
|
||||||
<p>
|
|
||||||
$maybe qcheck <- mbQcheck
|
|
||||||
_{MsgLmsAutomaticQueuing qcheck}
|
|
||||||
$nothing
|
|
||||||
_{MsgLmsManualQueuing}
|
|
||||||
<p>
|
|
||||||
^{btnForm}
|
|
||||||
Reference in New Issue
Block a user