fradrive/models/lms.model

154 lines
8.9 KiB
Plaintext

-- SPDX-FileCopyrightText: 2022 Sarah Vaupel <sarah.vaupel@ifi.lmu.de>,Steffen Jost <jost@tcs.ifi.lmu.de>
--
-- SPDX-License-Identifier: AGPL-3.0-or-later
Qualification
-- INVARIANT: 2*refreshWithin < validDuration
school SchoolId --TODO: Ansprechpartner der Schule in Briefe erwähnen
shorthand (CI Text)
name (CI Text)
description StoredMarkup Maybe -- user-defined large Html, ought to contain full description
validDuration Int Maybe -- > 0, qualification is valid indefinitely or for a specified number of months, use with addMonthsDay
auditDuration Int Maybe -- > 0, number of months to keep audit log and LmsUserIdents; or indefinitely (dangerous, since LmsIdents may run out)
refreshWithin CalendarDiffDays Maybe -- notify users about renewal within this number of month/days before expiry; to be used with addGregorianDurationClip
refreshReminder CalendarDiffDays Maybe -- send a second notification about renewal within this number of month/days before expiry
elearningStart Bool -- automatically schedule e-refresher
-- elearningOnly Bool -- successful E-learing automatically increases validity. NO!
expiryNotification Bool default=true -- should expiryNotification be generated for this qualification?
avsLicence AvsLicence Maybe -- if set, valid QualificationUsers are synchronized to AVS as a driving licence
sapId Text Maybe -- if set, valid QualificationUsers with userCompanyPersonalNumber are transmitted via SAP interface under this id
SchoolQualificationShort school shorthand -- must be unique per school and shorthand
SchoolQualificationName school name -- must be unique per school and name
-- across all schools, only one qualification may be a driving licence:
UniqueQualificationAvsLicence avsLicence !force
-- NOTE: two NULL values are not equal for the purpose of Uniqueness constraints!
deriving Eq Generic
-- TODOs:
-- - Enstehen Kosten, wenn Teilnehmer für KnowHow eingereiht werden, aber nicht am Kurs teilnehmen?
-- Falls ja, so sollte bei automatischem refresher vorher der Kunde durch FRADrive befragt werden?!
-- A: Der Inhaber per Email informieren!
-- A: Es kann gleich eine LMS Pin generiert und verschickt werden!
-- - Aufteilung Qualification "R" in zwei Teile: "R e-learning" und "R praxis" okay?
-- Besonderheiten:
-- - LmsIdent muss für alle Qualificationen einzigartig sein!
-- - Durchfallen wird mit UserList ständig erneut gesandt, bis Löschantrag gestellt wurde.
-- - Bestehen mit Result wird nur ein einziges mal gesendet! (Ausfallrisiko: keine Bestätigung der Kommunikation!)
-- - Explizites Löschen eines LmsIdent nach Success/Failure ist notwendig (feedback bei Block)
-- - LmsUser soll nur DELTA übermitteln. (GET Request will always return the same; until POST Request was processed!)
-- - PinReset==1 mit bestehendem Passwort kann problemlos erneut gesendet werden
-- - Flag "interner Mitarbeiter" wird von Know-How ignoriert / nicht ausgewertet (legacy)
QualificationPrecondition
qualification QualificationId OnDeleteCascade OnUpdateCascade -- AND: not unique, ie. qualification can have multiple required preconditions
required [QualificationId] -- OR : alternatives, any one will suffice
continuous Bool -- expiring precondition removes qualification
deriving Generic
-- TODO: connect Qualification with Exams!
QualificationEdit
user UserId
time UTCTime
qualification QualificationId OnDeleteCascade OnUpdateCascade
deriving Generic
QualificationUser
user UserId OnDeleteCascade OnUpdateCascade
qualification QualificationId OnDeleteCascade OnUpdateCascade
validUntil Day -- addGregorianMonthsRollOver (toInteger renewalMonths) qualificationUserValidUntil
lastRefresh Day -- lastRefresh > validUntil possible, if Qualification^elearningOnly == False
firstHeld Day -- first time the qualification was earned, should never change
scheduleRenewal Bool default=true -- if false, no automatic renewal is scheduled and the qualification expires
lastNotified UTCTime default=now() -- last notficiation about being invalid
-- Reasons and temporary revocations are implemented through QualificationUserBlock
-- TODO: adjust SAP interface to transmit end dates
UniqueQualificationUser qualification user
deriving Generic
QualificationUserBlock
qualificationUser QualificationUserId OnDeleteCascade OnUpdateCascade
unblock Bool
from UTCTime
reason Text
blocker UserId Maybe
deriving Eq Ord Read Show Generic
-- LMS Interface Tables, need regular processing by background jobs, per QualificationId:
--
-- 1. Daily Job: Add to LmsUser daily all qualification holders with
-- QualificationUserValidUntil >= now
-- /\ QualificationUserValudUntil <= now + QualificationRefreshWithin (time to schedule refresher)
-- /\ not already enlisted
--
-- 2. REST GET User.csv:
-- - where LmsUserReceived == Nothing \/ (LmsUserResetPin /\ LmsUserEnded == Nothing)
-- - delete-flag: isJust LmsUserStatus
-- Note: REST means that LmsUserResetPin and LmsUserDelete remain unchanged by this GET request!
--
-- 3. REST POST Userlist.csv: just save as is to LmsUserlist
--
-- 4. REST POST Ergebnisse.csv: just save as is to LmsResult
--
-- 5. When received: Job LmsUserlist: -- Note: containment needs at-once processing
-- - For all LmsUser:
-- + if contained:
-- set LmsUserReceived to Just now()
-- if LmsUserlistFailed: set LmsUserStatus to Just LmsBlocked now
-- + not contained, by LmsUserReceived is set: set LmsUserEnded to Just now()
-- - move row to LmsAudit
--
-- 6. When received: Daily Job LmsResult:
-- - set LmsUserReceived to Just now() -- always
-- - set LmsUserStatus to Just LmsSuccess now -- conditional
-- - and renew QualificationValidTo
-- - move row to LmsAudit
--
-- 7. Daily Job: dequeue LMS Users
-- - remove from LmsUser after audit Period has passed
LmsUser
qualification QualificationId OnDeleteCascade OnUpdateCascade
user UserId OnDeleteCascade OnUpdateCascade
ident LmsIdent -- must be unique accross all LMS courses!
pin Text
resetPin Bool default=false -- should pin be reset?
datePin UTCTime default=now() -- time pin was created
status LmsStatus Maybe -- open, success or failure; status should never change unless isNothing; isJust indicates lms is finished and user shall be deleted from LMS
--toDelete encoded by Handler.Utils.LMS.lmsUserToDelete
statusDay Day Maybe -- date of status change; should be isJust iff isJust status; modelling as a separate table too bothersome, unlike qualification block
started UTCTime default=now()
received UTCTime Maybe -- last acknowledgement by LMS
notified UTCTime Maybe -- last notified by FRADrive
ended UTCTime Maybe -- ident was deleted from LMS
-- Primary ident -- newtype Key LmsUserId = LmsUserKey { unLmsUser :: Text } -- change LmsIdent -> Text. Do we want this?
UniqueLmsIdent ident -- idents must be unique accross all qualifications, since idents are global within LMS!
UniqueLmsQualificationUser qualification user -- each user may be enrolled at most once per course
deriving Generic
-- LmsUserStatus
-- lmsUser LmsUserId OnDeleteCascade OnUpdateCascade
-- result LmsStatus -- data LmsStatus = LmsBlocked | LmsExpired | LmsSuccess
-- day Day
-- UniqueLmsUserStatus lmsUser -- enforcing uniqueness prohibits history
-- deriving Generic
-- LmsUserlist stores LMS upload for later processing only
LmsUserlist
qualification QualificationId OnDeleteCascade OnUpdateCascade
ident LmsIdent
failed Bool
timestamp UTCTime default=now()
UniqueLmsUserlist qualification ident
deriving Generic Show
-- LmsResult stores LMS upload for later processing only
LmsResult
qualification QualificationId OnDeleteCascade OnUpdateCascade
ident LmsIdent
success Day -- BEWARE: timezone is local as submitted by LMS
timestamp UTCTime default=now()
UniqueLmsResult qualification ident -- required by DBTable
deriving Generic