chore(lms): rethunk qualifcation model and process

This commit is contained in:
Steffen Jost 2022-02-16 16:48:28 +01:00
parent 3d3ac9d77c
commit 3656f1e6f1
2 changed files with 68 additions and 20 deletions

View File

@ -3,52 +3,99 @@ Qualification
shorthand (CI Text) shorthand (CI Text)
name (CI Text) name (CI Text)
description StoredMarkup Maybe -- user-defined large Html, ought to contain full description description StoredMarkup Maybe -- user-defined large Html, ought to contain full description
validDuration Word Maybe -- qualification is valid for this number of months validDuration Word Maybe -- qualification is valid for this number of months or indefinitely
auditDuration Word Maybe -- number of month to keep audit log auditDuration Word Maybe -- number of month to keep audit log
refreshWithin CalendarDiffDays Maybe -- refresher is scheduled within this number of month before expiry refreshWithin CalendarDiffDays Maybe -- automatically schedule e-refresher within this number of month/days before expiry
elearningOnly Bool -- successful E-learing automatically increases validity -- elearningOnly Bool -- successful E-learing automatically increases validity. NO!
-- refreshInvitation StoredMarkup -- hard-coded I18N-MSGs used instead, but displayed on qualification page -- refreshInvitation StoredMarkup -- hard-coded I18N-MSGs used instead, but displayed on qualification page NO!
-- expiryNotification StoredMarkup Maybe -- configurable user-profile-notifcations are used instead -- expiryNotification StoredMarkup Maybe -- configurable user-profile-notifcations are used instead NO!
UniqueSchoolShort school shorthand -- must be unique per school and shorthand UniqueSchoolShort school shorthand -- must be unique per school and shorthand
UniqueSchoolName school name -- must be unique per school and name UniqueSchoolName school name -- must be unique per school and name
deriving Generic deriving 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?!
-- - Aufteilung Qualification "R" in zwei Teile: "R e-learning" und "R exam" okay?
-- - Bedeutung LMS Übermittlung interner Mitarbeiter?
-- - LmsUser shall submit DELTA only: Beware, GET Request will always return the same; until POST Request was processed!
-- - Success/Failure: is an explicit LMS-delete still necessary?
-- - User: pin reset = 1 to existing pin problematic? Resubmission of existing users with pin causes which problems?
-- - ident unique for all qualifications F/R or duplicated? (F/R refreshers might be simultaneous)
QualificationPrecondition
qualification QualificationId -- 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 QualificationEdit
user User user User
time UTCTime time UTCTime
qualification QualificationId OnDeleteCascade OnUpdateCascade qualification QualificationId OnDeleteCascade OnUpdateCascade
deriving Generic deriving Generic
-- TODO: connect Qualification with Exams!
QualificationUser QualificationUser
user User user User
qualification QualificationId qualification QualificationId OnDeleteCascade OnUpdateCascade
validUntil UTCTime validUntil UTCTime
lastRefresh UTCTime -- lastRefresh > validUntil possible, if Qualification^elearningOnly == False lastRefresh UTCTime -- lastRefresh > validUntil possible, if Qualification^elearningOnly == False
firstHeld UTCTime -- first time the qualification was earned, should never change firstHeld UTCTime -- first time the qualification was earned, should never change
UniqueQualificationUser qualification user UniqueQualificationUser qualification user
deriving Generic deriving Generic
-- LMS Interface Tables, need regular processing by background jobs, per QualificationId:
--
-- 1. Daily Job: Add to LmsUser daily all qualification holders with
-- 0 <= QualificationUserValidUntil - now < QualificationRefreshWithin (time to schedule refresher)
-- /\ now - max(LmsUserStarted) > QualificationRefreshWithin (not already enlisted; Problem: QualificationELearningOnly!)
-- generate fresh ident and pin. (Bools?)
--
-- 2. REST GET User.csv:
-- - where LmsUserReceived == Nothing \/ (LmsUserResetPin /\ LmsUserEnded == Nothing)
-- - delete-flag: isJust LmsUserSuccess
-- Note: REST means that LmsUserResetPin and LmsUserDelete remain unchanged by this GET request!
--
-- 3. REST POST Userlist.csv:
-- -- save as is to LmsUserlist
-- -- change LmsUserEnded from Nothing to Just now, if not included in received list
--
-- 4. REST POST Ergebnisse.csv: just save as is to LmsResult
--
-- 5. Daily Job LmsUserlist: -- Note: containment needs at-once processing
-- - For all LmsUser:
-- + if contained, set LmsUserReceived to Just now()
-- + otherwise, set LmsUserEnded to Just now()
-- - if LmsUserlistFailed:
-- + set LmsUserSuccess to Just False
-- + set LmsUserDelete to True
-- - move row to LmsAudit
--
-- 6. Daily Job LmsResult:
-- - set LmsUserReceived to Just now()
-- - set LmsUserSuccess to Just True
-- - move row to LmsAudit
-- LMS Interface Tables, need regular processing by background jobs
LmsUser LmsUser
qualification QualificationId qualification QualificationId OnDeleteCascade OnUpdateCascade
user UserId user UserId
ident LmsIdent ident LmsIdent
pin Text pin Text
resetPin Bool -- should the pin be reset? resetPin Bool default=false -- should pin be reset?
delete Bool -- should the ident be deleted? TODO: do we need this? success Bool Maybe -- open, success or failure; isJust indicates user will be deleted from LMS
started UTCTime Maybe -- success LmsNotification --this would also encode Day information?!
submitted UTCTime Maybe -- ident was sent to LMS (should happen only once) started UTCTime default=now()
ended UTCTime Maybe -- ident was deleted in LMS received UTCTime Maybe -- last acknowledgement by LMS
ended UTCTime Maybe -- ident was deleted from LMS
UniqueLmsUser qualification ident UniqueLmsUser qualification ident
deriving Generic deriving Generic
-- LmsUserlist stores LMS upload ofr later processing only -- LmsUserlist stores LMS upload ofr later processing only
LmsUserlist LmsUserlist
qualification QualificationId qualification QualificationId OnDeleteCascade OnUpdateCascade
ident LmsIdent ident LmsIdent
failed Bool failed Bool
timestamp UTCTime default=now() timestamp UTCTime default=now()
@ -56,7 +103,7 @@ LmsUserlist
-- LmsUserlist stores LMS upload ofr later processing only -- LmsUserlist stores LMS upload ofr later processing only
LmsResult LmsResult
qualification QualificationId qualification QualificationId OnDeleteCascade OnUpdateCascade
ident LmsIdent ident LmsIdent
success Day success Day
timestamp UTCTime default=now() timestamp UTCTime default=now()
@ -67,6 +114,6 @@ LmsAudit
qualification QualificationId qualification QualificationId
ident LmsIdent ident LmsIdent
notificationType LmsNotification notificationType LmsNotification
received UTCTime received UTCTime -- timestamp from LmsUserlist/LmsResult
processed UTCTime default=now() processed UTCTime default=now()
deriving Generic deriving Generic

View File

@ -18,7 +18,8 @@ newtype LmsIdent = LmsIdent { getLmsIdent :: Text }
makeLenses_ ''LmsIdent makeLenses_ ''LmsIdent
data LmsNotification = LmsAlive | LmsBlocked | LmsSuccesss Day -- TODO: is this a good idea? Maybe just an ordinary Enum and a separate Day Column in the DB would be better, especially since LmsBlocked should really also encode a Day
data LmsNotification = LmsOpen | LmsBlocked | LmsSuccess Day
deriving (Eq, Ord, Read, Show, Generic, Typeable, NFData) deriving (Eq, Ord, Read, Show, Generic, Typeable, NFData)
deriveJSON defaultOptions deriveJSON defaultOptions