chore(qualficiation): proof of concept qualification renewal code

This commit is contained in:
Steffen Jost 2023-02-10 19:14:25 +01:00
parent cefbfad00d
commit e466f001d8
5 changed files with 58 additions and 20 deletions

View File

@ -45,5 +45,7 @@ TutorialUsersDeregistered count@Int64: #{show count} #{pluralDE count "-Tutorium
TutorialUserDeregister: Vom Tutorium Abmelden TutorialUserDeregister: Vom Tutorium Abmelden
TutorialUserSendMail: Mitteilung verschicken TutorialUserSendMail: Mitteilung verschicken
TutorialUserGrantQualification: Qualifikation vergeben TutorialUserGrantQualification: Qualifikation vergeben
TutorialUserRenewQualification: Qualifikation regulär verlängern
TutorialUserRenewedQualification n@Int: Qualifikation für #{tshow n} Tutoriums-#{pluralDE n "Teilnehmer:in" "Teilnehmer:innen"} regulär verlängert
TutorialUserGrantedQualification n@Int: Qualifikation erfolgreich an #{tshow n} Tutoriums-#{pluralDE n "Teilnehmer:in" "Teilnehmer:innen"} vergeben TutorialUserGrantedQualification n@Int: Qualifikation erfolgreich an #{tshow n} Tutoriums-#{pluralDE n "Teilnehmer:in" "Teilnehmer:innen"} vergeben
CommTutorial: Tutorium-Mitteilung CommTutorial: Tutorium-Mitteilung

View File

@ -46,5 +46,7 @@ TutorialUsersDeregistered count: Successfully deregistered #{show count} partici
TutorialUserDeregister: Deregister from tutorial TutorialUserDeregister: Deregister from tutorial
TutorialUserSendMail: Send mail TutorialUserSendMail: Send mail
TutorialUserGrantQualification: Grant Qualification TutorialUserGrantQualification: Grant Qualification
TutorialUserRenewQualification: Renew Qualification
TutorialUserRenewedQualification n@Int: Successfully renewed qualification #{tshow n} tutorial #{pluralEN n "user" "users"}
TutorialUserGrantedQualification n: Successfully granted qualification #{tshow n} tutorial #{pluralEN n "user" "users"} TutorialUserGrantedQualification n: Successfully granted qualification #{tshow n} tutorial #{pluralEN n "user" "users"}
CommTutorial: Tutorial message CommTutorial: Tutorial message

View File

@ -38,7 +38,7 @@ module Database.Esqueleto.Utils
, unKey , unKey
, selectCountRows, selectCountDistinct , selectCountRows, selectCountDistinct
, selectMaybe , selectMaybe
, day, diffDays, diffTimes , day, interval, diffDays, diffTimes
, exprLift , exprLift
, explicitUnsafeCoerceSqlExprValue , explicitUnsafeCoerceSqlExprValue
, module Database.Esqueleto.Utils.TH , module Database.Esqueleto.Utils.TH
@ -65,6 +65,8 @@ import Crypto.Hash (Digest, SHA256)
import Data.Coerce (Coercible) import Data.Coerce (Coercible)
import Data.Time.Clock (NominalDiffTime) import Data.Time.Clock (NominalDiffTime)
import Data.Time.Calendar (CalendarDiffDays)
import Data.Time.Format.ISO8601 (iso8601Show)
import qualified Data.Text.Lazy.Builder as Text.Builder import qualified Data.Text.Lazy.Builder as Text.Builder
@ -525,6 +527,14 @@ selectMaybe = fmap listToMaybe . E.select . (<* E.limit 1)
day :: E.SqlExpr (E.Value UTCTime) -> E.SqlExpr (E.Value Day) day :: E.SqlExpr (E.Value UTCTime) -> E.SqlExpr (E.Value Day)
day = E.unsafeSqlCastAs "date" day = E.unsafeSqlCastAs "date"
interval :: CalendarDiffDays -> E.SqlExpr (E.Value Day) -- E.+=. requires both types to be the same, so we use Day
-- interval _ = E.unsafeSqlCastAs "interval" $ E.unsafeSqlValue "'P2Y'" -- tested working example
interval = E.unsafeSqlCastAs "interval". E.unsafeSqlValue . wrapSqlString . Text.Builder.fromString . iso8601Show
where
singleQuote = Text.Builder.singleton '\''
wrapSqlString b = singleQuote <> b <> singleQuote
infixl 6 `diffDays`, `diffTimes` infixl 6 `diffDays`, `diffTimes`
diffDays :: E.SqlExpr (E.Value Day) -> E.SqlExpr (E.Value Day) -> E.SqlExpr (E.Value Int) diffDays :: E.SqlExpr (E.Value Day) -> E.SqlExpr (E.Value Day) -> E.SqlExpr (E.Value Int)

View File

@ -26,10 +26,11 @@ import Handler.Course.Users
data TutorialUserAction data TutorialUserAction
= TutorialUserGrantQualification = TutorialUserRenewQualification
| TutorialUserSendMail | TutorialUserGrantQualification
| TutorialUserDeregister | TutorialUserSendMail
deriving (Eq, Ord, Enum, Bounded, Read, Show, Generic) | TutorialUserDeregister
deriving (Eq, Ord, Enum, Bounded, Read, Show, Generic)
instance Universe TutorialUserAction instance Universe TutorialUserAction
instance Finite TutorialUserAction instance Finite TutorialUserAction
@ -37,13 +38,15 @@ nullaryPathPiece ''TutorialUserAction $ camelToPathPiece' 2
embedRenderMessage ''UniWorX ''TutorialUserAction id embedRenderMessage ''UniWorX ''TutorialUserAction id
data TutorialUserActionData data TutorialUserActionData
= TutorialUserGrantQualificationData = TutorialUserRenewQualificationData
{ tuQualification :: QualificationId { tuQualification :: QualificationId }
, tuValidUntil :: Day | TutorialUserGrantQualificationData
} { tuQualification :: QualificationId
| TutorialUserSendMailData , tuValidUntil :: Day
| TutorialUserDeregisterData{} }
deriving (Eq, Ord, Read, Show, Generic) | TutorialUserSendMailData
| TutorialUserDeregisterData{}
deriving (Eq, Ord, Read, Show, Generic)
getTUsersR, postTUsersR :: TermId -> SchoolId -> CourseShorthand -> TutorialName -> Handler Html getTUsersR, postTUsersR :: TermId -> SchoolId -> CourseShorthand -> TutorialName -> Handler Html
@ -85,7 +88,11 @@ postTUsersR tid ssh csh tutn = do
} }
acts :: Map TutorialUserAction (AForm Handler TutorialUserActionData) acts :: Map TutorialUserAction (AForm Handler TutorialUserActionData)
acts = Map.fromList acts = Map.fromList
[ ( TutorialUserGrantQualification [ ( TutorialUserRenewQualification
, TutorialUserRenewQualificationData
<$> apopt (selectField . fmap mkOptionList $ mapM qualOpt qualifications) (fslI MsgQualificationName) Nothing
)
, ( TutorialUserGrantQualification
, TutorialUserGrantQualificationData , TutorialUserGrantQualificationData
<$> apopt (selectField . fmap mkOptionList $ mapM qualOpt qualifications) (fslI MsgQualificationName) Nothing <$> apopt (selectField . fmap mkOptionList $ mapM qualOpt qualifications) (fslI MsgQualificationName) Nothing
<*> apopt dayField (fslI MsgLmsQualificationValidUntil) dayExpiry <*> apopt dayField (fslI MsgLmsQualificationValidUntil) dayExpiry
@ -103,6 +110,10 @@ postTUsersR tid ssh csh tutn = do
runDB . forM_ selectedUsers $ upsertQualificationUser tuQualification today tuValidUntil Nothing runDB . forM_ selectedUsers $ upsertQualificationUser tuQualification today tuValidUntil Nothing
addMessageI Success . MsgTutorialUserGrantedQualification $ Set.size selectedUsers addMessageI Success . MsgTutorialUserGrantedQualification $ Set.size selectedUsers
redirect $ CTutorialR tid ssh csh tutn TUsersR redirect $ CTutorialR tid ssh csh tutn TUsersR
(TutorialUserRenewQualificationData{..}, selectedUsers) -> do
noks <- runDB $ renewQualificationUsers tuQualification $ Set.toList selectedUsers
addMessageI (if noks == Set.size selectedUsers then Success else Warning) $ MsgTutorialUserRenewedQualification noks
redirect $ CTutorialR tid ssh csh tutn TUsersR
(TutorialUserSendMailData{}, selectedUsers) -> do (TutorialUserSendMailData{}, selectedUsers) -> do
cids <- traverse encrypt $ Set.toList selectedUsers :: Handler [CryptoUUIDUser] cids <- traverse encrypt $ Set.toList selectedUsers :: Handler [CryptoUUIDUser]
redirect (CTutorialR tid ssh csh tutn TCommR, [(toPathPiece GetRecipient, toPathPiece cID) | cID <- cids]) redirect (CTutorialR tid ssh csh tutn TCommR, [(toPathPiece GetRecipient, toPathPiece cID) | cID <- cids])

View File

@ -3,13 +3,15 @@
-- SPDX-License-Identifier: AGPL-3.0-or-later -- SPDX-License-Identifier: AGPL-3.0-or-later
module Handler.Utils.Qualification module Handler.Utils.Qualification
( module Handler.Utils.Qualification ( module Handler.Utils.Qualification
) where ) where
import Import import Import
-- import Data.Time.Calendar (CalendarDiffDays(..))
import qualified Database.Esqueleto.Experimental as E -- might need TypeApplications Lang-Pragma
import qualified Database.Esqueleto.Utils as E
upsertQualificationUser :: QualificationId -> Day -> Day -> Maybe Bool -> UserId -> DB () upsertQualificationUser :: QualificationId -> Day -> Day -> Maybe Bool -> UserId -> DB ()
upsertQualificationUser qualificationUserQualification qualificationUserLastRefresh qualificationUserValidUntil mbScheduleRenewal qualificationUserUser = do upsertQualificationUser qualificationUserQualification qualificationUserLastRefresh qualificationUserValidUntil mbScheduleRenewal qualificationUserUser = do
@ -35,3 +37,14 @@ upsertQualificationUser qualificationUserQualification qualificationUserLastRef
, transactionQualificationValidUntil = qualificationUserValidUntil , transactionQualificationValidUntil = qualificationUserValidUntil
, transactionQualificationScheduleRenewal = mbScheduleRenewal , transactionQualificationScheduleRenewal = mbScheduleRenewal
} }
renewQualificationUsers :: QualificationId -> [UserId] -> DB Int
renewQualificationUsers qid uids = do
--TODO: user updateWhere Count instead
E.update $ \qu -> do
E.set qu [ QualificationUserValidUntil E.+=. E.interval (CalendarDiffDays 2 0) ] -- TODO: for Testing only
E.where_ $ (qu E.^. QualificationUserQualification E.==. E.val qid )
E.&&. (qu E.^. QualificationUserUser `E.in_` E.valList uids)
-- TODO: AUDIT LOG!!!
-- forM_ uids $ \quid -> audit
return (-1)