152 lines
7.4 KiB
Haskell
152 lines
7.4 KiB
Haskell
{-# LANGUAGE TypeApplications #-}
|
|
|
|
module Jobs.Handler.LMS
|
|
( dispatchJobLmsEnqueue
|
|
, dispatchJobLmsDequeue
|
|
, dispatchJobLmsResults
|
|
, dispatchJobLmsUserlist
|
|
) where
|
|
|
|
import Import
|
|
|
|
-- import Jobs.Handler.Intervals.Utils
|
|
import qualified Database.Esqueleto.Experimental as E
|
|
--import qualified Database.Esqueleto.Legacy as E
|
|
-- import qualified Database.Esqueleto.PostgreSQL as E -- for insertSelect variant
|
|
import qualified Database.Esqueleto.Utils as E
|
|
|
|
-- import Handler.Utils.DateTime (addDiffDays)
|
|
|
|
dispatchJobLmsEnqueue :: QualificationId -> JobHandler UniWorX
|
|
dispatchJobLmsEnqueue _qid = JobHandlerAtomic act
|
|
where
|
|
-- act :: YesodJobDB UniWorX ()
|
|
act = hoist lift $ do
|
|
{-
|
|
now <- liftIO getCurrentTime
|
|
mbq <- E.selectOne $ E.from $ \quali -> E.where_ (quali E.^. QualificationId E.==. E.val qid) >> pure quali
|
|
-- Just quali <- get qid
|
|
|
|
let (Entity _ quali) = fromMaybe (error "TODO") mbq -- HACK / TODO
|
|
refreshTime = fromMaybe (error "TODO") $ qualificationRefreshWithin quali -- HACK / TODO
|
|
freshIdent = LmsIdent "abcd" -- TODO
|
|
freshPin = "1234" -- TODO
|
|
cutoff = addDiffDays refreshTime now
|
|
|
|
E.insertSelect ( do
|
|
quser <- E.from (E.table @QualificationUser)
|
|
E.where_ ( quser E.^. QualificationUserQualification E.==. E.val qid
|
|
E.&&. quser E.^. QualificationUserValidUntil E.>=. E.val now
|
|
E.&&. quser E.^. QualificationUserValidUntil E.<=. E.val cutoff
|
|
-- and not exists already as LMS User
|
|
)
|
|
|
|
return $ LmsUser
|
|
E.<# E.val qid
|
|
E.<&> (quser E.^. QualificationUserUser)
|
|
E.<&> E.val freshIdent -- ident -- THIS IS A PROBLEM! MUST ALSO BE UNIQUE!
|
|
E.<&> E.val freshPin -- pin -- THIS IS A PROBLEM!
|
|
E.<&> E.false -- reset
|
|
E.<&> E.nothing -- status
|
|
E.<&> E.val now -- started
|
|
E.<&> E.nothing -- received
|
|
E.<&> E.nothing -- ended
|
|
)
|
|
|
|
-- find qualification holders
|
|
-}
|
|
error "lms dequeu stub"
|
|
|
|
dispatchJobLmsDequeue :: QualificationId -> JobHandler UniWorX
|
|
dispatchJobLmsDequeue _qid =
|
|
-- wenn bestanden: qualification verlängern & LmsIdent löschen
|
|
-- wenn durchgefallen: LmsIdent löschen
|
|
-- wenn Zeit abgelaufen: LmsIdent löschen
|
|
error "lms dequeu stub"
|
|
|
|
dispatchJobLmsResults :: QualificationId -> JobHandler UniWorX
|
|
dispatchJobLmsResults qid = JobHandlerAtomic act
|
|
where
|
|
-- act :: YesodJobDB UniWorX ()
|
|
act = hoist lift $ do
|
|
now <- liftIO getCurrentTime
|
|
{- Unfortunately, we cannot use insertSelect due to Haskell-Type changes and deletion of keys
|
|
E.insertSelectWithConflict
|
|
(UniqueLmsUser $ error "insertSelectWithConflict inspected constraint") -- never executed, just a type hint
|
|
(do
|
|
(luser E.:& lresult) <-
|
|
E.from $ E.table @LmsUser `E.innerJoin` E.table @LmsResult `E.on` (\(luser E.:& lresult) -> luser E.^. LmsUserIdent E.==. lresult E.^. LmsResultIdent
|
|
E.&&. luser E.^. LmsUserQualification E.==. lresult E.^. LmsResultQualification
|
|
)
|
|
E.where_ $ lresult E.^. LmsResultQualification E.==. E.val qid
|
|
return $ LmsUser E.<# E.val qid
|
|
E.<&> (luser E.^. LmsUserUser)
|
|
E.<&> (luser E.^. LmsUserIdent)
|
|
E.<&> (luser E.^. LmsUserPin)
|
|
E.<&> (luser E.^. LmsUserResetPin)
|
|
E.<&> (E.val $ (LmsSuccess . E.unValue) <$> (lresult E.^. LmsResultSuccess)) -- how to convert Day to LmsStatus here?
|
|
E.<&> (luser E.^. LmsUserStarted)
|
|
E.<&> E.just (lresult E.^. LmsResultTimestamp)
|
|
E.<&> (luser E.^. LmsUserEnded)
|
|
)
|
|
(\current _excluded ->
|
|
[ LmsUserStatus E.=. current E.^. LmsUserStatus, LmsUserReceived E.=. current E.^. LmsUserReceived ] -- I believe this list could just be empty, since excluded is not uses?!
|
|
)
|
|
-- Unclear how to delete here
|
|
-}
|
|
-- result :: [(Entity LmsUser, Entity LmsResult)]
|
|
results <- E.select $ do
|
|
(luser E.:& lresult) <- E.from $
|
|
E.table @LmsUser `E.innerJoin` E.table @LmsResult
|
|
`E.on` (\(luser E.:& lresult) -> luser E.^. LmsUserIdent E.==. lresult E.^. LmsResultIdent
|
|
E.&&. luser E.^. LmsUserQualification E.==. lresult E.^. LmsResultQualification)
|
|
E.where_ $ luser E.^. LmsUserQualification E.==. E.val qid
|
|
E.&&. E.isNothing (luser E.^. LmsUserEnded) -- do not process closed learners
|
|
return (luser, lresult)
|
|
forM_ results $ \(Entity luid luser, Entity lrid lresult) -> do
|
|
-- three separate DB operations per result is not so nice. All within one transaction though.
|
|
let lreceived = lmsResultTimestamp lresult
|
|
lstatus = lmsResultSuccess lresult & LmsSuccess
|
|
-- always log success, since this is only transmitted once
|
|
update luid [ LmsUserStatus =. Just lstatus
|
|
, LmsUserReceived =. Just lreceived
|
|
]
|
|
insert_ $ LmsAudit qid (lmsUserIdent luser) lstatus lreceived now
|
|
delete lrid
|
|
$logInfoS "LmsResult" [st|Processed ${tshow (length results)} LMS results|]
|
|
|
|
dispatchJobLmsUserlist :: QualificationId -> JobHandler UniWorX
|
|
dispatchJobLmsUserlist qid = JobHandlerAtomic act
|
|
where
|
|
-- act :: YesodJobDB UniWorX ()
|
|
act = hoist lift $ do
|
|
now <- liftIO getCurrentTime
|
|
-- result :: [(Entity LmsUser, Entity LmsUserlist)]
|
|
results <- E.select $ do
|
|
(luser E.:& lulist) <- E.from $
|
|
E.table @LmsUser `E.leftJoin` E.table @LmsUserlist
|
|
`E.on` (\(luser E.:& lulist) -> luser E.^. LmsUserIdent E.=?. lulist E.?. LmsUserlistIdent
|
|
E.&&. luser E.^. LmsUserQualification E.=?. lulist E.?. LmsUserlistQualification)
|
|
E.where_ $ luser E.^. LmsUserQualification E.==. E.val qid
|
|
E.&&. E.isNothing (luser E.^. LmsUserEnded) -- do not process closed learners
|
|
return (luser, lulist)
|
|
forM_ results $ \case
|
|
(Entity luid luser, Nothing)
|
|
| isJust $ lmsUserReceived luser
|
|
, isNothing $ lmsUserEnded luser ->
|
|
update luid [LmsUserEnded =. Just now]
|
|
| otherwise -> return () -- likely not yet started
|
|
|
|
(Entity luid luser, Just (Entity lulid lulist)) -> do
|
|
let usrNoStat = isNothing $ lmsUserStatus luser
|
|
lBlocked = lmsUserlistFailed lulist
|
|
updStatus = lBlocked && usrNoStat -- only update empty status to blocked
|
|
lReceived = lmsUserlistTimestamp lulist
|
|
lStatus = LmsBlocked $ utctDay lReceived
|
|
update luid $ [ LmsUserStatus =. Just lStatus | updStatus ]
|
|
<> [ LmsUserReceived =. Just lReceived ]
|
|
when lBlocked . insert_ $ LmsAudit qid (lmsUserIdent luser) lStatus lReceived now -- always log blocked
|
|
delete lulid
|
|
|
|
$logInfoS "LmsUserlist" [st|Processed LMS Userlist with ${tshow (length results)} entries|]
|