feat(courses): add NotificationCourseRegistered
This commit is contained in:
parent
64b391a0fe
commit
3750da81dc
@ -777,6 +777,11 @@ MailSubmissionRatedIntro courseName@Text termDesc@Text: Ihre Abgabe im Kurs #{co
|
|||||||
MailSubjectSheetActive csh@CourseShorthand sheetName@SheetName: #{sheetName} in #{csh} wurde herausgegeben
|
MailSubjectSheetActive csh@CourseShorthand sheetName@SheetName: #{sheetName} in #{csh} wurde herausgegeben
|
||||||
MailSheetActiveIntro courseName@Text termDesc@Text sheetName@SheetName: Sie können nun #{sheetName} im Kurs #{courseName} (#{termDesc}) herunterladen.
|
MailSheetActiveIntro courseName@Text termDesc@Text sheetName@SheetName: Sie können nun #{sheetName} im Kurs #{courseName} (#{termDesc}) herunterladen.
|
||||||
|
|
||||||
|
MailSubjectCourseRegistered csh@CourseShorthand: Sie wurden zu #{csh} angemeldet
|
||||||
|
MailSubjectCourseRegisteredOther displayName@Text csh@CourseShorthand: #{displayName} wurde zu #{csh} angemeldet
|
||||||
|
MailCourseRegisteredIntro courseName@Text termDesc@Text: Sie wurden im Kurs #{courseName} (#{termDesc}) angemeldet.
|
||||||
|
MailCourseRegisteredIntroOther displayName@Text courseName@Text termDesc@Text: #{displayName} wurde im Kurs #{courseName} (#{termDesc}) angemeldet.
|
||||||
|
|
||||||
MailSubjectExamResult csh@CourseShorthand examn@ExamName: Ergebnisse für #{examn} in #{csh} wurden herausgegeben
|
MailSubjectExamResult csh@CourseShorthand examn@ExamName: Ergebnisse für #{examn} in #{csh} wurden herausgegeben
|
||||||
MailExamResultIntro courseName@Text termDesc@Text examn@ExamName: Sie können nun Ihr Ergebnis für #{examn} im Kurs #{courseName} (#{termDesc}) einsehen.
|
MailExamResultIntro courseName@Text termDesc@Text examn@ExamName: Sie können nun Ihr Ergebnis für #{examn} im Kurs #{courseName} (#{termDesc}) einsehen.
|
||||||
|
|
||||||
@ -829,7 +834,7 @@ InvitationAcceptDecline: Einladung annehmen/ablehnen
|
|||||||
InvitationFromTip displayName@Text: Sie erhalten diese Einladung, weil #{displayName} ihren Versand in Uni2work ausgelöst hat.
|
InvitationFromTip displayName@Text: Sie erhalten diese Einladung, weil #{displayName} ihren Versand in Uni2work ausgelöst hat.
|
||||||
InvitationUniWorXTip: Uni2work ist ein webbasiertes Lehrverwaltungssystem der LMU München.
|
InvitationUniWorXTip: Uni2work ist ein webbasiertes Lehrverwaltungssystem der LMU München.
|
||||||
|
|
||||||
MailSubjectParticipantInvitation tid@TermId ssh@SchoolId csh@CourseShorthand: [#{tid}-#{ssh}-#{csh}] Einladung zum Kursteilname
|
MailSubjectParticipantInvitation tid@TermId ssh@SchoolId csh@CourseShorthand: [#{tid}-#{ssh}-#{csh}] Einladung zur Kursteilnahme
|
||||||
|
|
||||||
MailSubjectCorrectorInvitation tid@TermId ssh@SchoolId csh@CourseShorthand shn@SheetName: [#{tid}-#{ssh}-#{csh}] Einladung zum Korrektor für #{shn}
|
MailSubjectCorrectorInvitation tid@TermId ssh@SchoolId csh@CourseShorthand shn@SheetName: [#{tid}-#{ssh}-#{csh}] Einladung zum Korrektor für #{shn}
|
||||||
|
|
||||||
@ -909,12 +914,14 @@ NotificationTriggerAllocationUnratedApplications: Bewertungen zu Zentralanmeldun
|
|||||||
NotificationTriggerAllocationResults: Plätze wurden für eine meiner Zentralanmeldungen verteilt
|
NotificationTriggerAllocationResults: Plätze wurden für eine meiner Zentralanmeldungen verteilt
|
||||||
NotificationTriggerExamOfficeExamResults: Ich kann neue Prüfungsergebnisse einsehen
|
NotificationTriggerExamOfficeExamResults: Ich kann neue Prüfungsergebnisse einsehen
|
||||||
NotificationTriggerExamOfficeExamResultsChanged: Prüfungsergebnisse wurden verändert
|
NotificationTriggerExamOfficeExamResultsChanged: Prüfungsergebnisse wurden verändert
|
||||||
|
NotificationTriggerCourseRegistered: Ein Kursverwalter hat mich zu einem Kurs angemeldet
|
||||||
|
|
||||||
NotificationTriggerKindAll: Für alle Benutzer
|
NotificationTriggerKindAll: Für alle Benutzer
|
||||||
NotificationTriggerKindCourseParticipant: Für Kursteilnehmer
|
NotificationTriggerKindCourseParticipant: Für Kursteilnehmer
|
||||||
NotificationTriggerKindExamParticipant: Für Prüfungsteilnehmer
|
NotificationTriggerKindExamParticipant: Für Prüfungsteilnehmer
|
||||||
NotificationTriggerKindCorrector: Für Korrektoren
|
NotificationTriggerKindCorrector: Für Korrektoren
|
||||||
NotificationTriggerKindLecturer: Für Dozenten
|
NotificationTriggerKindLecturer: Für Dozenten
|
||||||
|
NotificationTriggerKindCourseLecturer: Für Kursverwalter
|
||||||
NotificationTriggerKindAdmin: Für Administratoren
|
NotificationTriggerKindAdmin: Für Administratoren
|
||||||
NotificationTriggerKindExamOffice: Für das Prüfungsamt
|
NotificationTriggerKindExamOffice: Für das Prüfungsamt
|
||||||
NotificationTriggerKindEvaluation: Für Vorlesungsumfragen
|
NotificationTriggerKindEvaluation: Für Vorlesungsumfragen
|
||||||
|
|||||||
@ -169,10 +169,9 @@ addParticipantsResultMessages AddParticipantsResult{..} = execWriterT $ do
|
|||||||
tell . pure <=< messageI Success . MsgCourseParticipantsRegistered $ length aurSuccess
|
tell . pure <=< messageI Success . MsgCourseParticipantsRegistered $ length aurSuccess
|
||||||
|
|
||||||
|
|
||||||
registerUser :: (MonadHandler m, HandlerSite m ~ UniWorX, MonadCatch m)
|
registerUser :: CourseId
|
||||||
=> CourseId
|
|
||||||
-> UserId
|
-> UserId
|
||||||
-> WriterT AddParticipantsResult (ReaderT (YesodPersistBackend UniWorX) m) ()
|
-> WriterT AddParticipantsResult (YesodJobDB UniWorX) ()
|
||||||
registerUser cid uid = exceptT tell tell $ do
|
registerUser cid uid = exceptT tell tell $ do
|
||||||
whenM (lift . lift . existsBy $ UniqueParticipant uid cid) $
|
whenM (lift . lift . existsBy $ UniqueParticipant uid cid) $
|
||||||
throwError $ mempty { aurAlreadyRegistered = Set.singleton uid }
|
throwError $ mempty { aurAlreadyRegistered = Set.singleton uid }
|
||||||
@ -197,6 +196,7 @@ registerUser cid uid = exceptT tell tell $ do
|
|||||||
, ..
|
, ..
|
||||||
}
|
}
|
||||||
lift . lift . audit $ TransactionCourseParticipantEdit cid uid
|
lift . lift . audit $ TransactionCourseParticipantEdit cid uid
|
||||||
|
lift . lift . queueDBJob . JobQueueNotification $ NotificationCourseRegistered uid cid
|
||||||
|
|
||||||
return $ case courseParticipantField of
|
return $ case courseParticipantField of
|
||||||
Nothing -> mempty { aurNoUniquePrimaryField = Set.singleton uid }
|
Nothing -> mempty { aurNoUniquePrimaryField = Set.singleton uid }
|
||||||
|
|||||||
@ -16,6 +16,8 @@ import Text.Blaze.Html.Renderer.Text (renderHtml)
|
|||||||
|
|
||||||
import Handler.Course.Register
|
import Handler.Course.Register
|
||||||
|
|
||||||
|
import Jobs.Queue
|
||||||
|
|
||||||
|
|
||||||
getCUserR, postCUserR :: TermId -> SchoolId -> CourseShorthand -> CryptoUUIDUser -> Handler Html
|
getCUserR, postCUserR :: TermId -> SchoolId -> CourseShorthand -> CryptoUUIDUser -> Handler Html
|
||||||
getCUserR = postCUserR
|
getCUserR = postCUserR
|
||||||
@ -161,9 +163,10 @@ postCUserR tid ssh csh uCId = do
|
|||||||
= Just featId
|
= Just featId
|
||||||
| otherwise
|
| otherwise
|
||||||
= Nothing
|
= Nothing
|
||||||
pId <- runDB $ do
|
pId <- runDBJobs $ do
|
||||||
pId <- insertUnique $ CourseParticipant cid uid now field Nothing
|
pId <- insertUnique $ CourseParticipant cid uid now field Nothing
|
||||||
when (is _Just pId) $
|
when (is _Just pId) $ do
|
||||||
|
queueDBJob . JobQueueNotification $ NotificationCourseRegistered uid cid
|
||||||
audit $ TransactionCourseParticipantEdit cid uid
|
audit $ TransactionCourseParticipantEdit cid uid
|
||||||
return pId
|
return pId
|
||||||
case pId of
|
case pId of
|
||||||
|
|||||||
@ -151,6 +151,7 @@ postEAddUserR tid ssh csh examn = do
|
|||||||
, ..
|
, ..
|
||||||
}
|
}
|
||||||
lift . lift . audit $ TransactionCourseParticipantEdit cid uid
|
lift . lift . audit $ TransactionCourseParticipantEdit cid uid
|
||||||
|
lift . lift . queueDBJob . JobQueueNotification $ NotificationCourseRegistered uid cid
|
||||||
lift $ lift examRegister
|
lift $ lift examRegister
|
||||||
|
|
||||||
return $ case courseParticipantField of
|
return $ case courseParticipantField of
|
||||||
|
|||||||
@ -18,6 +18,8 @@ import qualified Data.Set as Set
|
|||||||
import Text.Hamlet (ihamlet)
|
import Text.Hamlet (ihamlet)
|
||||||
|
|
||||||
import Data.Aeson hiding (Result(..))
|
import Data.Aeson hiding (Result(..))
|
||||||
|
|
||||||
|
import Jobs.Queue
|
||||||
|
|
||||||
|
|
||||||
instance IsInvitableJunction ExamRegistration where
|
instance IsInvitableJunction ExamRegistration where
|
||||||
@ -98,6 +100,7 @@ examRegistrationInvitationConfig = InvitationConfig{..}
|
|||||||
invitationInsertHook (Entity eid Exam{..}) _ ExamRegistration{..} mField act = do
|
invitationInsertHook (Entity eid Exam{..}) _ ExamRegistration{..} mField act = do
|
||||||
whenIsJust mField $ \cpField -> do
|
whenIsJust mField $ \cpField -> do
|
||||||
insert_ $ CourseParticipant examCourse examRegistrationUser examRegistrationTime cpField Nothing
|
insert_ $ CourseParticipant examCourse examRegistrationUser examRegistrationTime cpField Nothing
|
||||||
|
queueDBJob . JobQueueNotification $ NotificationCourseRegistered examRegistrationUser examCourse
|
||||||
audit $ TransactionCourseParticipantEdit examCourse examRegistrationUser
|
audit $ TransactionCourseParticipantEdit examCourse examRegistrationUser
|
||||||
|
|
||||||
let doAudit = audit $ TransactionExamRegister eid examRegistrationUser
|
let doAudit = audit $ TransactionExamRegister eid examRegistrationUser
|
||||||
|
|||||||
@ -37,6 +37,8 @@ import Database.Persist.Sql (deleteWhereCount, updateWhereCount)
|
|||||||
|
|
||||||
import Control.Lens.Indexed ((<.), (.>))
|
import Control.Lens.Indexed ((<.), (.>))
|
||||||
|
|
||||||
|
import Jobs.Queue
|
||||||
|
|
||||||
|
|
||||||
type ExamUserTableExpr = ( E.SqlExpr (Entity ExamRegistration)
|
type ExamUserTableExpr = ( E.SqlExpr (Entity ExamRegistration)
|
||||||
`E.InnerJoin` E.SqlExpr (Entity User)
|
`E.InnerJoin` E.SqlExpr (Entity User)
|
||||||
@ -744,6 +746,7 @@ postEUsersR tid ssh csh examn = do
|
|||||||
, courseParticipantField = examUserCsvActCourseField
|
, courseParticipantField = examUserCsvActCourseField
|
||||||
, courseParticipantAllocated = Nothing
|
, courseParticipantAllocated = Nothing
|
||||||
}
|
}
|
||||||
|
queueDBJob . JobQueueNotification $ NotificationCourseRegistered examUserCsvActUser examCourse
|
||||||
audit $ TransactionCourseParticipantEdit examCourse examUserCsvActUser
|
audit $ TransactionCourseParticipantEdit examCourse examUserCsvActUser
|
||||||
insert_ ExamRegistration
|
insert_ ExamRegistration
|
||||||
{ examRegistrationExam = eid
|
{ examRegistrationExam = eid
|
||||||
|
|||||||
@ -49,6 +49,7 @@ data NotificationTriggerKind
|
|||||||
| NTKCourseParticipant
|
| NTKCourseParticipant
|
||||||
| NTKExamParticipant
|
| NTKExamParticipant
|
||||||
| NTKCorrector
|
| NTKCorrector
|
||||||
|
| NTKCourseLecturer
|
||||||
| NTKAllocationStaff
|
| NTKAllocationStaff
|
||||||
| NTKAllocationParticipant
|
| NTKAllocationParticipant
|
||||||
| NTKFunctionary SchoolFunction
|
| NTKFunctionary SchoolFunction
|
||||||
@ -61,6 +62,7 @@ instance RenderMessage UniWorX NotificationTriggerKind where
|
|||||||
NTKCourseParticipant -> mr MsgNotificationTriggerKindCourseParticipant
|
NTKCourseParticipant -> mr MsgNotificationTriggerKindCourseParticipant
|
||||||
NTKExamParticipant -> mr MsgNotificationTriggerKindExamParticipant
|
NTKExamParticipant -> mr MsgNotificationTriggerKindExamParticipant
|
||||||
NTKCorrector -> mr MsgNotificationTriggerKindCorrector
|
NTKCorrector -> mr MsgNotificationTriggerKindCorrector
|
||||||
|
NTKCourseLecturer -> mr MsgNotificationTriggerKindCourseLecturer
|
||||||
NTKAllocationStaff -> mr MsgNotificationTriggerKindAllocationStaff
|
NTKAllocationStaff -> mr MsgNotificationTriggerKindAllocationStaff
|
||||||
NTKAllocationParticipant -> mr MsgNotificationTriggerKindAllocationParticipant
|
NTKAllocationParticipant -> mr MsgNotificationTriggerKindAllocationParticipant
|
||||||
NTKFunctionary SchoolAdmin -> mr MsgNotificationTriggerKindAdmin
|
NTKFunctionary SchoolAdmin -> mr MsgNotificationTriggerKindAdmin
|
||||||
@ -153,6 +155,10 @@ notificationForm template = wFormToAForm $ do
|
|||||||
, NTKExamParticipant <- nt
|
, NTKExamParticipant <- nt
|
||||||
= fmap not . E.selectExists . E.from $ \examRegistration ->
|
= fmap not . E.selectExists . E.from $ \examRegistration ->
|
||||||
E.where_ $ examRegistration E.^. ExamRegistrationUser E.==. E.val uid
|
E.where_ $ examRegistration E.^. ExamRegistrationUser E.==. E.val uid
|
||||||
|
| Just uid <- mbUid
|
||||||
|
, NTKCourseLecturer <- nt
|
||||||
|
= fmap not . E.selectExists . E.from $ \lecturer ->
|
||||||
|
E.where_ $ lecturer E.^. LecturerUser E.==. E.val uid
|
||||||
| otherwise
|
| otherwise
|
||||||
= return False
|
= return False
|
||||||
|
|
||||||
@ -176,9 +182,9 @@ notificationForm template = wFormToAForm $ do
|
|||||||
NTSubmissionRated -> Just NTKCourseParticipant
|
NTSubmissionRated -> Just NTKCourseParticipant
|
||||||
NTSheetActive -> Just NTKCourseParticipant
|
NTSheetActive -> Just NTKCourseParticipant
|
||||||
NTSheetSoonInactive -> Just NTKCourseParticipant
|
NTSheetSoonInactive -> Just NTKCourseParticipant
|
||||||
NTSheetInactive -> Just $ NTKFunctionary SchoolLecturer
|
NTSheetInactive -> Just NTKCourseLecturer
|
||||||
NTCorrectionsAssigned -> Just NTKCorrector
|
NTCorrectionsAssigned -> Just NTKCorrector
|
||||||
NTCorrectionsNotDistributed -> Just $ NTKFunctionary SchoolLecturer
|
NTCorrectionsNotDistributed -> Just NTKCourseLecturer
|
||||||
NTUserRightsUpdate -> Just NTKAll
|
NTUserRightsUpdate -> Just NTKAll
|
||||||
NTUserAuthModeUpdate -> Just NTKAll
|
NTUserAuthModeUpdate -> Just NTKAll
|
||||||
NTExamRegistrationActive -> Just NTKCourseParticipant
|
NTExamRegistrationActive -> Just NTKCourseParticipant
|
||||||
@ -193,6 +199,7 @@ notificationForm template = wFormToAForm $ do
|
|||||||
NTAllocationResults -> Just NTKAllocationParticipant
|
NTAllocationResults -> Just NTKAllocationParticipant
|
||||||
NTExamOfficeExamResults -> Just $ NTKFunctionary SchoolExamOffice
|
NTExamOfficeExamResults -> Just $ NTKFunctionary SchoolExamOffice
|
||||||
NTExamOfficeExamResultsChanged -> Just $ NTKFunctionary SchoolExamOffice
|
NTExamOfficeExamResultsChanged -> Just $ NTKFunctionary SchoolExamOffice
|
||||||
|
NTCourseRegistered -> Just NTKAll
|
||||||
-- _other -> Nothing
|
-- _other -> Nothing
|
||||||
|
|
||||||
forcedTriggers = [NTUserRightsUpdate, NTUserAuthModeUpdate]
|
forcedTriggers = [NTUserRightsUpdate, NTUserAuthModeUpdate]
|
||||||
|
|||||||
@ -134,7 +134,7 @@ data InvitationConfig junction = forall formCtx. InvitationConfig
|
|||||||
-- ^ Additional restrictions to check before allowing an user to redeem an invitation token
|
-- ^ Additional restrictions to check before allowing an user to redeem an invitation token
|
||||||
, invitationForm :: Entity (InvitationFor junction) -> InvitationData junction -> Key User -> AForm (YesodDB UniWorX) (InvitableJunction junction, formCtx)
|
, invitationForm :: Entity (InvitationFor junction) -> InvitationData junction -> Key User -> AForm (YesodDB UniWorX) (InvitableJunction junction, formCtx)
|
||||||
-- ^ Assimilate the additional data entered by the redeeming user
|
-- ^ Assimilate the additional data entered by the redeeming user
|
||||||
, invitationInsertHook :: forall a. Entity (InvitationFor junction) -> InvitationData junction -> junction -> formCtx -> (DB a -> DB a)
|
, invitationInsertHook :: forall a. Entity (InvitationFor junction) -> InvitationData junction -> junction -> formCtx -> (YesodJobDB UniWorX a -> YesodJobDB UniWorX a)
|
||||||
-- ^ Perform additional actions before or after insertion of the junction into the database
|
-- ^ Perform additional actions before or after insertion of the junction into the database
|
||||||
, invitationSuccessMsg :: Entity (InvitationFor junction) -> Entity junction -> DB (SomeMessage UniWorX)
|
, invitationSuccessMsg :: Entity (InvitationFor junction) -> Entity junction -> DB (SomeMessage UniWorX)
|
||||||
-- ^ What to tell the redeeming user after accepting the invitation
|
-- ^ What to tell the redeeming user after accepting the invitation
|
||||||
@ -368,8 +368,8 @@ invitationR' InvitationConfig{..} = liftHandler $ do
|
|||||||
invitee <- requireAuthId
|
invitee <- requireAuthId
|
||||||
cRoute <- fromMaybe (error "invitationR' called from 404-handler") <$> getCurrentRoute
|
cRoute <- fromMaybe (error "invitationR' called from 404-handler") <$> getCurrentRoute
|
||||||
|
|
||||||
(tRoute, (dataWidget, dataEnctype), heading, explanation) <- runDB $ do
|
(tRoute, (dataWidget, dataEnctype), heading, explanation) <- runDBJobs $ do
|
||||||
fEnt@(Entity fid _) <- invitationResolveFor itData >>= (\k -> Entity k <$> get404 k)
|
fEnt@(Entity fid _) <- hoist lift (invitationResolveFor itData) >>= (\k -> Entity k <$> get404 k)
|
||||||
dbData <- case ephemeralInvitation @junction of
|
dbData <- case ephemeralInvitation @junction of
|
||||||
Nothing -> do
|
Nothing -> do
|
||||||
Invitation{..} <- entityVal <$> getBy404 (UniqueInvitation itEmail $ invRef @junction fid)
|
Invitation{..} <- entityVal <$> getBy404 (UniqueInvitation itEmail $ invRef @junction fid)
|
||||||
@ -380,8 +380,8 @@ invitationR' InvitationConfig{..} = liftHandler $ do
|
|||||||
let
|
let
|
||||||
iData :: InvitationData junction
|
iData :: InvitationData junction
|
||||||
iData = review _InvitationData (dbData, itData)
|
iData = review _InvitationData (dbData, itData)
|
||||||
guardAuthResult =<< invitationRestriction fEnt iData
|
guardAuthResult =<< hoist lift (invitationRestriction fEnt iData)
|
||||||
((dataRes, dataWidget), dataEnctype) <- runFormPost . formEmbedJwtPost . renderAForm FormStandard . wFormToAForm $ do
|
((dataRes, dataWidget), dataEnctype) <- hoist lift . runFormPost . formEmbedJwtPost . renderAForm FormStandard . wFormToAForm $ do
|
||||||
dataRes <- aFormToWForm $ invitationForm fEnt iData invitee
|
dataRes <- aFormToWForm $ invitationForm fEnt iData invitee
|
||||||
btnRes <- aFormToWForm . disambiguateButtons $ combinedButtonField (BtnInviteAccept : [ BtnInviteDecline | is _Nothing $ ephemeralInvitation @junction ]) (fslI MsgInvitationAction & bool id (setTooltip MsgInvitationActionTip) (is _Nothing $ ephemeralInvitation @junction))
|
btnRes <- aFormToWForm . disambiguateButtons $ combinedButtonField (BtnInviteAccept : [ BtnInviteDecline | is _Nothing $ ephemeralInvitation @junction ]) (fslI MsgInvitationAction & bool id (setTooltip MsgInvitationActionTip) (is _Nothing $ ephemeralInvitation @junction))
|
||||||
case btnRes of
|
case btnRes of
|
||||||
@ -390,8 +390,8 @@ invitationR' InvitationConfig{..} = liftHandler $ do
|
|||||||
|
|
||||||
MsgRenderer mr <- getMsgRenderer
|
MsgRenderer mr <- getMsgRenderer
|
||||||
ur <- getUrlRenderParams
|
ur <- getUrlRenderParams
|
||||||
heading <- invitationHeading fEnt iData
|
heading <- hoist lift $ invitationHeading fEnt iData
|
||||||
explanation <- (\ihtml -> ihtml (toHtml . mr) ur) <$> invitationExplanation fEnt iData
|
explanation <- (\ihtml -> ihtml (toHtml . mr) ur) <$> hoist lift (invitationExplanation fEnt iData)
|
||||||
|
|
||||||
fmap (, (dataWidget, dataEnctype), heading, explanation) . formResultMaybe dataRes $ \case
|
fmap (, (dataWidget, dataEnctype), heading, explanation) . formResultMaybe dataRes $ \case
|
||||||
Nothing -> do
|
Nothing -> do
|
||||||
@ -405,8 +405,8 @@ invitationR' InvitationConfig{..} = liftHandler $ do
|
|||||||
Nothing -> invalidArgsI [MsgInvitationCollision]
|
Nothing -> invalidArgsI [MsgInvitationCollision]
|
||||||
Just res -> do
|
Just res -> do
|
||||||
deleteBy . UniqueInvitation itEmail $ invRef @junction fid
|
deleteBy . UniqueInvitation itEmail $ invRef @junction fid
|
||||||
addMessageI Success =<< invitationSuccessMsg fEnt res
|
addMessageI Success =<< hoist lift (invitationSuccessMsg fEnt res)
|
||||||
Just <$> invitationUltDest fEnt res
|
Just <$> hoist lift (invitationUltDest fEnt res)
|
||||||
|
|
||||||
whenIsJust tRoute redirect
|
whenIsJust tRoute redirect
|
||||||
|
|
||||||
|
|||||||
@ -120,6 +120,8 @@ import Data.Dynamic
|
|||||||
|
|
||||||
import qualified Data.Csv as Csv
|
import qualified Data.Csv as Csv
|
||||||
|
|
||||||
|
import Jobs.Queue
|
||||||
|
|
||||||
|
|
||||||
#if MIN_VERSION_base(4,11,0)
|
#if MIN_VERSION_base(4,11,0)
|
||||||
type Monoid' = Monoid
|
type Monoid' = Monoid
|
||||||
@ -545,7 +547,7 @@ data DBTCsvDecode r' k' csv = forall route csvAction csvActionClass csvException
|
|||||||
, dbtCsvComputeActions :: DBCsvDiff r' csv k' -> ConduitT () csvAction (YesodDB UniWorX) ()
|
, dbtCsvComputeActions :: DBCsvDiff r' csv k' -> ConduitT () csvAction (YesodDB UniWorX) ()
|
||||||
, dbtCsvClassifyAction :: csvAction -> csvActionClass
|
, dbtCsvClassifyAction :: csvAction -> csvActionClass
|
||||||
, dbtCsvCoarsenActionClass :: csvActionClass -> DBCsvActionMode
|
, dbtCsvCoarsenActionClass :: csvActionClass -> DBCsvActionMode
|
||||||
, dbtCsvExecuteActions :: ConduitT csvAction Void (YesodDB UniWorX) route
|
, dbtCsvExecuteActions :: ConduitT csvAction Void (YesodJobDB UniWorX) route
|
||||||
, dbtCsvRenderKey :: Map k' r' -> csvAction -> Widget
|
, dbtCsvRenderKey :: Map k' r' -> csvAction -> Widget
|
||||||
, dbtCsvRenderActionClass :: csvActionClass -> Widget
|
, dbtCsvRenderActionClass :: csvActionClass -> Widget
|
||||||
, dbtCsvRenderException :: csvException -> YesodDB UniWorX Text
|
, dbtCsvRenderException :: csvException -> YesodDB UniWorX Text
|
||||||
@ -1190,7 +1192,7 @@ dbTable PSValidator{..} dbtable@DBTable{ dbtIdent = dbtIdent'@(toPathPiece -> db
|
|||||||
addMessageI Info MsgCsvImportAborted
|
addMessageI Info MsgCsvImportAborted
|
||||||
redirect $ tblLink id
|
redirect $ tblLink id
|
||||||
| otherwise -> FormSuccess $ do
|
| otherwise -> FormSuccess $ do
|
||||||
finalDest <- runConduit $ C.sourceList acts .| dbtCsvExecuteActions
|
finalDest <- runDBJobs' . runConduit $ C.sourceList acts .| dbtCsvExecuteActions
|
||||||
addMessageI Success . MsgCsvImportSuccessful $ length acts
|
addMessageI Success . MsgCsvImportSuccessful $ length acts
|
||||||
E.transactionSave
|
E.transactionSave
|
||||||
redirect finalDest
|
redirect finalDest
|
||||||
|
|||||||
@ -210,6 +210,8 @@ determineNotificationCandidates NotificationAllocationResults{..} =
|
|||||||
E.where_ $ isStudent E.||. isLecturer
|
E.where_ $ isStudent E.||. isLecturer
|
||||||
|
|
||||||
return user
|
return user
|
||||||
|
determineNotificationCandidates NotificationCourseRegistered{..} =
|
||||||
|
maybeToList <$> getEntity nUser
|
||||||
|
|
||||||
|
|
||||||
classifyNotification :: Notification -> DB NotificationTrigger
|
classifyNotification :: Notification -> DB NotificationTrigger
|
||||||
@ -237,3 +239,4 @@ classifyNotification NotificationAllocationUnratedApplications{} = return NTAll
|
|||||||
classifyNotification NotificationExamOfficeExamResults{} = return NTExamOfficeExamResults
|
classifyNotification NotificationExamOfficeExamResults{} = return NTExamOfficeExamResults
|
||||||
classifyNotification NotificationExamOfficeExamResultsChanged{} = return NTExamOfficeExamResultsChanged
|
classifyNotification NotificationExamOfficeExamResultsChanged{} = return NTExamOfficeExamResultsChanged
|
||||||
classifyNotification NotificationAllocationResults{} = return NTAllocationResults
|
classifyNotification NotificationAllocationResults{} = return NTAllocationResults
|
||||||
|
classifyNotification NotificationCourseRegistered{} = return NTCourseRegistered
|
||||||
|
|||||||
@ -18,6 +18,7 @@ import Jobs.Handler.SendNotification.ExamActive
|
|||||||
import Jobs.Handler.SendNotification.ExamResult
|
import Jobs.Handler.SendNotification.ExamResult
|
||||||
import Jobs.Handler.SendNotification.Allocation
|
import Jobs.Handler.SendNotification.Allocation
|
||||||
import Jobs.Handler.SendNotification.ExamOffice
|
import Jobs.Handler.SendNotification.ExamOffice
|
||||||
|
import Jobs.Handler.SendNotification.CourseRegistered
|
||||||
|
|
||||||
|
|
||||||
dispatchJobSendNotification :: UserId -> Notification -> Handler ()
|
dispatchJobSendNotification :: UserId -> Notification -> Handler ()
|
||||||
|
|||||||
35
src/Jobs/Handler/SendNotification/CourseRegistered.hs
Normal file
35
src/Jobs/Handler/SendNotification/CourseRegistered.hs
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
{-# OPTIONS_GHC -fno-warn-unused-do-bind #-} -- ihamletFile discards do results
|
||||||
|
|
||||||
|
module Jobs.Handler.SendNotification.CourseRegistered
|
||||||
|
( dispatchNotificationCourseRegistered
|
||||||
|
) where
|
||||||
|
|
||||||
|
import Import
|
||||||
|
|
||||||
|
import Handler.Utils.Mail
|
||||||
|
import Jobs.Handler.SendNotification.Utils
|
||||||
|
|
||||||
|
import Text.Hamlet
|
||||||
|
import qualified Data.CaseInsensitive as CI
|
||||||
|
|
||||||
|
dispatchNotificationCourseRegistered :: UserId -> CourseId -> UserId -> Handler ()
|
||||||
|
dispatchNotificationCourseRegistered nUser nCourse jRecipient = userMailT jRecipient $ do
|
||||||
|
(User{..}, Course{..}) <- liftHandler . runDB $ (,) <$> getJust nUser <*> getJust nCourse
|
||||||
|
|
||||||
|
let isSelf = nUser == jRecipient
|
||||||
|
|
||||||
|
replaceMailHeader "Auto-Submitted" $ Just "auto-generated"
|
||||||
|
setSubjectI $ if
|
||||||
|
| isSelf -> MsgMailSubjectCourseRegistered courseShorthand
|
||||||
|
| otherwise -> MsgMailSubjectCourseRegisteredOther userDisplayName courseShorthand
|
||||||
|
|
||||||
|
MsgRenderer mr <- getMailMsgRenderer
|
||||||
|
let termDesc = mr . ShortTermIdentifier $ unTermKey courseTerm
|
||||||
|
tid = courseTerm
|
||||||
|
ssh = courseSchool
|
||||||
|
csh = courseShorthand
|
||||||
|
|
||||||
|
editNotifications <- mkEditNotifications jRecipient
|
||||||
|
|
||||||
|
addAlternatives $
|
||||||
|
providePreferredAlternative ($(ihamletFile "templates/mail/courseRegistered.hamlet") :: HtmlUrlI18n UniWorXMessage (Route UniWorX))
|
||||||
@ -4,6 +4,7 @@ module Jobs.Queue
|
|||||||
, queueJob, queueJob'
|
, queueJob, queueJob'
|
||||||
, YesodJobDB
|
, YesodJobDB
|
||||||
, runDBJobs, queueDBJob, sinkDBJobs
|
, runDBJobs, queueDBJob, sinkDBJobs
|
||||||
|
, runDBJobs'
|
||||||
, queueDBJobCron
|
, queueDBJobCron
|
||||||
, module Jobs.Types
|
, module Jobs.Types
|
||||||
) where
|
) where
|
||||||
@ -29,6 +30,8 @@ import qualified Data.Conduit.List as C
|
|||||||
import Data.Semigroup ((<>))
|
import Data.Semigroup ((<>))
|
||||||
|
|
||||||
import UnliftIO.Concurrent (myThreadId)
|
import UnliftIO.Concurrent (myThreadId)
|
||||||
|
|
||||||
|
import Control.Monad.Trans.Resource (register)
|
||||||
|
|
||||||
|
|
||||||
data JobQueueException = JobQueuePoolEmpty
|
data JobQueueException = JobQueuePoolEmpty
|
||||||
@ -128,3 +131,17 @@ runDBJobs act = do
|
|||||||
app <- getYesod
|
app <- getYesod
|
||||||
forM_ jIds $ flip runReaderT app . writeJobCtl . JobCtlPerform
|
forM_ jIds $ flip runReaderT app . writeJobCtl . JobCtlPerform
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
|
|
||||||
|
runDBJobs' :: YesodJobDB UniWorX a -> DB a
|
||||||
|
runDBJobs' act = do
|
||||||
|
(ret, jIds) <- mapReaderT runWriterT act
|
||||||
|
|
||||||
|
void . liftHandler $ do
|
||||||
|
UnliftIO{..} <- askUnliftIO
|
||||||
|
register . unliftIO . runDB $
|
||||||
|
forM_ jIds $ \jId ->
|
||||||
|
whenM (existsKey jId) $
|
||||||
|
runReaderT (writeJobCtl $ JobCtlPerform jId) =<< getYesod
|
||||||
|
|
||||||
|
return ret
|
||||||
|
|||||||
@ -88,6 +88,7 @@ data Notification = NotificationSubmissionRated { nSubmission :: SubmissionId }
|
|||||||
| NotificationExamOfficeExamResults { nExam :: ExamId }
|
| NotificationExamOfficeExamResults { nExam :: ExamId }
|
||||||
| NotificationExamOfficeExamResultsChanged { nExamResults :: Set ExamResultId }
|
| NotificationExamOfficeExamResultsChanged { nExamResults :: Set ExamResultId }
|
||||||
| NotificationAllocationResults { nAllocation :: AllocationId }
|
| NotificationAllocationResults { nAllocation :: AllocationId }
|
||||||
|
| NotificationCourseRegistered { nUser :: UserId, nCourse :: CourseId }
|
||||||
deriving (Eq, Ord, Show, Read, Generic, Typeable)
|
deriving (Eq, Ord, Show, Read, Generic, Typeable)
|
||||||
|
|
||||||
instance Hashable Job
|
instance Hashable Job
|
||||||
|
|||||||
@ -43,6 +43,7 @@ data NotificationTrigger
|
|||||||
| NTAllocationResults
|
| NTAllocationResults
|
||||||
| NTExamOfficeExamResults
|
| NTExamOfficeExamResults
|
||||||
| NTExamOfficeExamResultsChanged
|
| NTExamOfficeExamResultsChanged
|
||||||
|
| NTCourseRegistered
|
||||||
deriving (Eq, Ord, Read, Show, Enum, Bounded, Generic, Typeable)
|
deriving (Eq, Ord, Read, Show, Enum, Bounded, Generic, Typeable)
|
||||||
|
|
||||||
instance Universe NotificationTrigger
|
instance Universe NotificationTrigger
|
||||||
|
|||||||
21
templates/mail/courseRegistered.hamlet
Normal file
21
templates/mail/courseRegistered.hamlet
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
$newline never
|
||||||
|
\<!doctype html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<style>
|
||||||
|
h1 {
|
||||||
|
font-size: 1.25em;
|
||||||
|
font-variant: small-caps;
|
||||||
|
font-weight: normal;
|
||||||
|
}
|
||||||
|
<body>
|
||||||
|
<h1>
|
||||||
|
$if isSelf
|
||||||
|
_{MsgMailCourseRegisteredIntro (CI.original courseName) termDesc}
|
||||||
|
$else
|
||||||
|
_{MsgMailCourseRegisteredIntroOther userDisplayName (CI.original courseName) termDesc}
|
||||||
|
<p>
|
||||||
|
<a href=@{CourseR tid ssh csh CShowR}>
|
||||||
|
#{courseName}
|
||||||
|
^{editNotifications}
|
||||||
Reference in New Issue
Block a user