feat(external-exams): auditing
This commit is contained in:
parent
1252a5fc79
commit
2b153c1863
@ -139,6 +139,36 @@ data Transaction
|
|||||||
{ transactionTutorial :: TutorialId
|
{ transactionTutorial :: TutorialId
|
||||||
}
|
}
|
||||||
|
|
||||||
|
| TransactionExternalExamEdit
|
||||||
|
{ transactionExternalExam :: ExternalExamId
|
||||||
|
}
|
||||||
|
|
||||||
|
| TransactionExternalExamOfficeSchoolEdit
|
||||||
|
{ transactionExternalExam :: ExternalExamId
|
||||||
|
, transactionSchool :: SchoolId
|
||||||
|
}
|
||||||
|
| TransactionExternalExamOfficeSchoolDelete
|
||||||
|
{ transactionExternalExam :: ExternalExamId
|
||||||
|
, transactionSchool :: SchoolId
|
||||||
|
}
|
||||||
|
|
||||||
|
| TransactionExternalExamStaffEdit
|
||||||
|
{ transactionExternalExam :: ExternalExamId
|
||||||
|
, transactionUser :: UserId
|
||||||
|
}
|
||||||
|
| TransactionExternalExamStaffDelete
|
||||||
|
{ transactionExternalExam :: ExternalExamId
|
||||||
|
, transactionUser :: UserId
|
||||||
|
}
|
||||||
|
| TransactionExternalExamStaffInviteEdit
|
||||||
|
{ transactionExternalExam :: ExternalExamId
|
||||||
|
, transactionEmail :: UserEmail
|
||||||
|
}
|
||||||
|
| TransactionExternalExamStaffInviteDelete
|
||||||
|
{ transactionExternalExam :: ExternalExamId
|
||||||
|
, transactionEmail :: UserEmail
|
||||||
|
}
|
||||||
|
|
||||||
deriving (Eq, Ord, Read, Show, Generic, Typeable)
|
deriving (Eq, Ord, Read, Show, Generic, Typeable)
|
||||||
|
|
||||||
deriveJSON defaultOptions
|
deriveJSON defaultOptions
|
||||||
|
|||||||
@ -75,7 +75,7 @@ lecturerInvitationConfig = InvitationConfig{..}
|
|||||||
where
|
where
|
||||||
toJunction jLecturerType = (JunctionLecturer{..}, ())
|
toJunction jLecturerType = (JunctionLecturer{..}, ())
|
||||||
lFs = fslI MsgLecturerType & setTooltip MsgCourseLecturerRightsIdentical
|
lFs = fslI MsgLecturerType & setTooltip MsgCourseLecturerRightsIdentical
|
||||||
invitationInsertHook _ _ _ _ = id
|
invitationInsertHook _ _ _ _ _ = id
|
||||||
invitationSuccessMsg (Entity _ Course{..}) (Entity _ Lecturer{..}) = do
|
invitationSuccessMsg (Entity _ Course{..}) (Entity _ Lecturer{..}) = do
|
||||||
MsgRenderer mr <- getMsgRenderer
|
MsgRenderer mr <- getMsgRenderer
|
||||||
return . SomeMessage $ MsgLecturerInvitationAccepted (mr lecturerType) courseShorthand
|
return . SomeMessage $ MsgLecturerInvitationAccepted (mr lecturerType) courseShorthand
|
||||||
|
|||||||
@ -91,7 +91,7 @@ participantInvitationConfig = InvitationConfig{..}
|
|||||||
studyFeatures <- wreq (studyFeaturesFieldFor Nothing False [] $ Just uid)
|
studyFeatures <- wreq (studyFeaturesFieldFor Nothing False [] $ Just uid)
|
||||||
(fslI MsgCourseStudyFeature & setTooltip MsgCourseStudyFeatureTip) Nothing
|
(fslI MsgCourseStudyFeature & setTooltip MsgCourseStudyFeatureTip) Nothing
|
||||||
return . fmap (, ()) $ JunctionParticipant <$> pure now <*> studyFeatures <*> pure Nothing
|
return . fmap (, ()) $ JunctionParticipant <$> pure now <*> studyFeatures <*> pure Nothing
|
||||||
invitationInsertHook _ _ CourseParticipant{..} _ act = do
|
invitationInsertHook _ _ _ CourseParticipant{..} _ act = do
|
||||||
res <- act
|
res <- act
|
||||||
audit $ TransactionCourseParticipantEdit courseParticipantCourse courseParticipantUser
|
audit $ TransactionCourseParticipantEdit courseParticipantCourse courseParticipantUser
|
||||||
return res
|
return res
|
||||||
|
|||||||
@ -71,7 +71,7 @@ examCorrectorInvitationConfig = InvitationConfig{..}
|
|||||||
return $ InvitationTokenConfig itAuthority Nothing Nothing Nothing
|
return $ InvitationTokenConfig itAuthority Nothing Nothing Nothing
|
||||||
invitationRestriction _ _ = return Authorized
|
invitationRestriction _ _ = return Authorized
|
||||||
invitationForm _ _ _ = pure (JunctionExamCorrector, ())
|
invitationForm _ _ _ = pure (JunctionExamCorrector, ())
|
||||||
invitationInsertHook _ _ _ _ = id
|
invitationInsertHook _ _ _ _ _ = id
|
||||||
invitationSuccessMsg (Entity _ Exam{..}) _ = return . SomeMessage $ MsgExamCorrectorInvitationAccepted examName
|
invitationSuccessMsg (Entity _ Exam{..}) _ = return . SomeMessage $ MsgExamCorrectorInvitationAccepted examName
|
||||||
invitationUltDest (Entity _ Exam{..}) _ = do
|
invitationUltDest (Entity _ Exam{..}) _ = do
|
||||||
Course{..} <- get404 examCourse
|
Course{..} <- get404 examCourse
|
||||||
|
|||||||
@ -97,7 +97,7 @@ examRegistrationInvitationConfig = InvitationConfig{..}
|
|||||||
fieldRes <- wreq (studyFeaturesFieldFor Nothing False [] $ Just uid) (fslI MsgCourseStudyFeature) Nothing
|
fieldRes <- wreq (studyFeaturesFieldFor Nothing False [] $ Just uid) (fslI MsgCourseStudyFeature) Nothing
|
||||||
return $ (JunctionExamRegistration invDBExamRegistrationOccurrence now, ) . Just <$> fieldRes
|
return $ (JunctionExamRegistration invDBExamRegistrationOccurrence now, ) . Just <$> fieldRes
|
||||||
(True , _ ) -> return $ pure (JunctionExamRegistration invDBExamRegistrationOccurrence now, Nothing)
|
(True , _ ) -> return $ pure (JunctionExamRegistration invDBExamRegistrationOccurrence now, Nothing)
|
||||||
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
|
queueDBJob . JobQueueNotification $ NotificationCourseRegistered examRegistrationUser examCourse
|
||||||
|
|||||||
@ -74,7 +74,7 @@ examOfficeUserInvitationConfig = InvitationConfig{..}
|
|||||||
return InvitationTokenConfig{..}
|
return InvitationTokenConfig{..}
|
||||||
invitationRestriction _ _ = return Authorized
|
invitationRestriction _ _ = return Authorized
|
||||||
invitationForm _ _ _ = pure (JunctionExamOfficeUser, ())
|
invitationForm _ _ _ = pure (JunctionExamOfficeUser, ())
|
||||||
invitationInsertHook _ _ ExamOfficeUser{..} _ act = do
|
invitationInsertHook _ _ _ ExamOfficeUser{..} _ act = do
|
||||||
res <- act
|
res <- act
|
||||||
audit $ TransactionExamOfficeUserAdd examOfficeUserOffice examOfficeUserUser
|
audit $ TransactionExamOfficeUserAdd examOfficeUserOffice examOfficeUserUser
|
||||||
return res
|
return res
|
||||||
|
|||||||
@ -53,23 +53,31 @@ postEEEditR tid ssh coursen examn = do
|
|||||||
, externalExamShowGrades = eefShowGrades
|
, externalExamShowGrades = eefShowGrades
|
||||||
}
|
}
|
||||||
when (is _Nothing replaceRes) $ do
|
when (is _Nothing replaceRes) $ do
|
||||||
|
audit $ TransactionExternalExamEdit eeId
|
||||||
|
|
||||||
forM_ (eefStaff `setSymmDiff` staff) $ \change -> if
|
forM_ (eefStaff `setSymmDiff` staff) $ \change -> if
|
||||||
| change `Set.member` eefStaff -> case change of
|
| change `Set.member` eefStaff -> case change of
|
||||||
Left invEmail ->
|
Left invEmail -> do
|
||||||
|
audit $ TransactionExternalExamStaffInviteEdit eeId invEmail
|
||||||
sinkInvitationsF externalExamStaffInvitationConfig
|
sinkInvitationsF externalExamStaffInvitationConfig
|
||||||
[(invEmail, eeId, (InvDBDataExternalExamStaff, InvTokenDataExternalExamStaff))]
|
[(invEmail, eeId, (InvDBDataExternalExamStaff, InvTokenDataExternalExamStaff))]
|
||||||
Right staffUid ->
|
Right staffUid -> do
|
||||||
insert_ $ ExternalExamStaff staffUid eeId
|
audit $ TransactionExternalExamStaffEdit eeId staffUid
|
||||||
|
insert_ $ ExternalExamStaff staffUid eeId
|
||||||
| otherwise -> case change of
|
| otherwise -> case change of
|
||||||
Left invEmail ->
|
Left invEmail -> do
|
||||||
|
audit $ TransactionExternalExamStaffInviteDelete eeId invEmail
|
||||||
deleteInvitation @ExternalExamStaff eeId invEmail
|
deleteInvitation @ExternalExamStaff eeId invEmail
|
||||||
Right staffUid ->
|
Right staffUid -> do
|
||||||
|
audit $ TransactionExternalExamStaffDelete eeId staffUid
|
||||||
deleteBy $ UniqueExternalExamStaff eeId staffUid
|
deleteBy $ UniqueExternalExamStaff eeId staffUid
|
||||||
|
|
||||||
forM_ (eefOfficeSchools `setSymmDiff` schools) $ \change -> if
|
forM_ (eefOfficeSchools `setSymmDiff` schools) $ \change -> if
|
||||||
| change `Set.member` eefOfficeSchools ->
|
| change `Set.member` eefOfficeSchools -> do
|
||||||
|
audit $ TransactionExternalExamOfficeSchoolEdit eeId change
|
||||||
insert_ $ ExternalExamOfficeSchool change eeId
|
insert_ $ ExternalExamOfficeSchool change eeId
|
||||||
| otherwise ->
|
| otherwise -> do
|
||||||
|
audit $ TransactionExternalExamOfficeSchoolDelete eeId change
|
||||||
deleteBy $ UniqueExternalExamOfficeSchool eeId change
|
deleteBy $ UniqueExternalExamOfficeSchool eeId change
|
||||||
return replaceRes
|
return replaceRes
|
||||||
|
|
||||||
|
|||||||
@ -31,19 +31,29 @@ postEExamNewR = do
|
|||||||
, externalExamShowGrades = eefShowGrades
|
, externalExamShowGrades = eefShowGrades
|
||||||
}
|
}
|
||||||
whenIsJust insertRes $ \eeId -> do
|
whenIsJust insertRes $ \eeId -> do
|
||||||
insertMany_
|
audit $ TransactionExternalExamEdit eeId
|
||||||
[ ExternalExamOfficeSchool{..}
|
|
||||||
| externalExamOfficeSchoolSchool <- Set.toList eefOfficeSchools
|
let eefOfficeSchools' = do
|
||||||
, externalExamOfficeSchoolSchool /= eefSchool
|
externalExamOfficeSchoolSchool <- Set.toList eefOfficeSchools
|
||||||
, let externalExamOfficeSchoolExam = eeId
|
guard $ externalExamOfficeSchoolSchool /= eefSchool
|
||||||
]
|
let externalExamOfficeSchoolExam = eeId
|
||||||
|
return ExternalExamOfficeSchool{..}
|
||||||
|
insertMany_ eefOfficeSchools'
|
||||||
|
forM_ eefOfficeSchools' $ \ExternalExamOfficeSchool{..} ->
|
||||||
|
audit $ TransactionExternalExamOfficeSchoolEdit eeId externalExamOfficeSchoolSchool
|
||||||
|
|
||||||
let (invites, adds) = partitionEithers $ Set.toList eefStaff
|
let (invites, adds) = partitionEithers $ Set.toList eefStaff
|
||||||
insertMany_ [ ExternalExamStaff{..}
|
eefStaff' = do
|
||||||
| externalExamStaffUser <- adds
|
externalExamStaffUser <- adds
|
||||||
, let externalExamStaffExam = eeId
|
let externalExamStaffExam = eeId
|
||||||
]
|
return ExternalExamStaff{..}
|
||||||
|
insertMany_ eefStaff'
|
||||||
|
forM_ eefStaff' $ \ExternalExamStaff{..} ->
|
||||||
|
audit $ TransactionExternalExamStaffEdit eeId externalExamStaffUser
|
||||||
|
|
||||||
sinkInvitationsF externalExamStaffInvitationConfig $ map (, eeId, (InvDBDataExternalExamStaff, InvTokenDataExternalExamStaff)) invites
|
sinkInvitationsF externalExamStaffInvitationConfig $ map (, eeId, (InvDBDataExternalExamStaff, InvTokenDataExternalExamStaff)) invites
|
||||||
|
forM_ invites $ \invEmail ->
|
||||||
|
audit $ TransactionExternalExamStaffInviteEdit eeId invEmail
|
||||||
return insertRes
|
return insertRes
|
||||||
|
|
||||||
case insertRes of
|
case insertRes of
|
||||||
|
|||||||
@ -63,7 +63,12 @@ externalExamStaffInvitationConfig = InvitationConfig{..}
|
|||||||
return $ InvitationTokenConfig itAuthority Nothing (Just Nothing) Nothing
|
return $ InvitationTokenConfig itAuthority Nothing (Just Nothing) Nothing
|
||||||
invitationRestriction _ _ = return Authorized
|
invitationRestriction _ _ = return Authorized
|
||||||
invitationForm _ (InvDBDataExternalExamStaff, _) _ = pure (JunctionExternalExamStaff, ())
|
invitationForm _ (InvDBDataExternalExamStaff, _) _ = pure (JunctionExternalExamStaff, ())
|
||||||
invitationInsertHook _ _ _ _ = id
|
invitationInsertHook invEmail _ _ ExternalExamStaff{..} _ act = do
|
||||||
|
res <- act
|
||||||
|
|
||||||
|
audit $ TransactionExternalExamStaffInviteDelete externalExamStaffExam invEmail
|
||||||
|
audit $ TransactionExternalExamStaffEdit externalExamStaffExam externalExamStaffUser
|
||||||
|
return res
|
||||||
invitationSuccessMsg (Entity _ ExternalExam{..}) (Entity _ ExternalExamStaff{})
|
invitationSuccessMsg (Entity _ ExternalExam{..}) (Entity _ ExternalExamStaff{})
|
||||||
= return . SomeMessage $ MsgExternalExamStaffInvitationAccepted externalExamCourseName externalExamExamName
|
= return . SomeMessage $ MsgExternalExamStaffInvitationAccepted externalExamCourseName externalExamExamName
|
||||||
invitationUltDest (Entity _ ExternalExam{..}) _ = return . SomeRoute $ EExamR externalExamTerm externalExamSchool externalExamCourseName externalExamExamName EEShowR
|
invitationUltDest (Entity _ ExternalExam{..}) _ = return . SomeRoute $ EExamR externalExamTerm externalExamSchool externalExamCourseName externalExamExamName EEShowR
|
||||||
|
|||||||
@ -892,7 +892,7 @@ correctorInvitationConfig = InvitationConfig{..}
|
|||||||
return $ InvitationTokenConfig itAuthority Nothing Nothing Nothing
|
return $ InvitationTokenConfig itAuthority Nothing Nothing Nothing
|
||||||
invitationRestriction _ _ = return Authorized
|
invitationRestriction _ _ = return Authorized
|
||||||
invitationForm _ (InvDBDataSheetCorrector cLoad cState, _) _ = pure $ (JunctionSheetCorrector cLoad cState, ())
|
invitationForm _ (InvDBDataSheetCorrector cLoad cState, _) _ = pure $ (JunctionSheetCorrector cLoad cState, ())
|
||||||
invitationInsertHook _ _ _ _ = id
|
invitationInsertHook _ _ _ _ _ = id
|
||||||
invitationSuccessMsg (Entity _ Sheet{..}) _ = return . SomeMessage $ MsgCorrectorInvitationAccepted sheetName
|
invitationSuccessMsg (Entity _ Sheet{..}) _ = return . SomeMessage $ MsgCorrectorInvitationAccepted sheetName
|
||||||
invitationUltDest (Entity _ Sheet{..}) _ = do
|
invitationUltDest (Entity _ Sheet{..}) _ = do
|
||||||
Course{..} <- get404 sheetCourse
|
Course{..} <- get404 sheetCourse
|
||||||
|
|||||||
@ -114,7 +114,7 @@ submissionUserInvitationConfig = InvitationConfig{..}
|
|||||||
return InvitationTokenConfig{..}
|
return InvitationTokenConfig{..}
|
||||||
invitationRestriction _ _ = return Authorized
|
invitationRestriction _ _ = return Authorized
|
||||||
invitationForm _ _ _ = pure (JunctionSubmissionUser, ())
|
invitationForm _ _ _ = pure (JunctionSubmissionUser, ())
|
||||||
invitationInsertHook _ _ _ _ = id
|
invitationInsertHook _ _ _ _ _ = id
|
||||||
invitationSuccessMsg (Entity _ Submission{..}) _ = do
|
invitationSuccessMsg (Entity _ Submission{..}) _ = do
|
||||||
Sheet{..} <- getJust submissionSheet
|
Sheet{..} <- getJust submissionSheet
|
||||||
return . SomeMessage $ MsgSubmissionUserInvitationAccepted sheetName
|
return . SomeMessage $ MsgSubmissionUserInvitationAccepted sheetName
|
||||||
|
|||||||
@ -68,7 +68,7 @@ tutorInvitationConfig = InvitationConfig{..}
|
|||||||
return $ InvitationTokenConfig itAuthority Nothing Nothing Nothing
|
return $ InvitationTokenConfig itAuthority Nothing Nothing Nothing
|
||||||
invitationRestriction _ _ = return Authorized
|
invitationRestriction _ _ = return Authorized
|
||||||
invitationForm _ _ _ = pure (JunctionTutor, ())
|
invitationForm _ _ _ = pure (JunctionTutor, ())
|
||||||
invitationInsertHook _ _ _ _ = id
|
invitationInsertHook _ _ _ _ _ = id
|
||||||
invitationSuccessMsg (Entity _ Tutorial{..}) _ = return . SomeMessage $ MsgCorrectorInvitationAccepted tutorialName
|
invitationSuccessMsg (Entity _ Tutorial{..}) _ = return . SomeMessage $ MsgCorrectorInvitationAccepted tutorialName
|
||||||
invitationUltDest (Entity _ Tutorial{..}) _ = do
|
invitationUltDest (Entity _ Tutorial{..}) _ = do
|
||||||
Course{..} <- get404 tutorialCourse
|
Course{..} <- get404 tutorialCourse
|
||||||
|
|||||||
@ -579,7 +579,7 @@ functionInvitationConfig = InvitationConfig{..}
|
|||||||
return InvitationTokenConfig{..}
|
return InvitationTokenConfig{..}
|
||||||
invitationRestriction _ _ = return Authorized
|
invitationRestriction _ _ = return Authorized
|
||||||
invitationForm _ (_, InvTokenDataUserFunction{..}) _ = pure $ (JunctionUserFunction invTokenUserFunctionFunction, ())
|
invitationForm _ (_, InvTokenDataUserFunction{..}) _ = pure $ (JunctionUserFunction invTokenUserFunctionFunction, ())
|
||||||
invitationInsertHook _ _ _ _ = id
|
invitationInsertHook _ _ _ _ _ = id
|
||||||
invitationSuccessMsg (Entity _ School{..}) (Entity _ UserFunction{..}) = do
|
invitationSuccessMsg (Entity _ School{..}) (Entity _ UserFunction{..}) = do
|
||||||
MsgRenderer mr <- getMsgRenderer
|
MsgRenderer mr <- getMsgRenderer
|
||||||
return . SomeMessage . MsgSchoolFunctionInvitationAccepted schoolName $ mr userFunctionFunction
|
return . SomeMessage . MsgSchoolFunctionInvitationAccepted schoolName $ mr userFunctionFunction
|
||||||
|
|||||||
@ -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 -> (YesodJobDB UniWorX a -> YesodJobDB UniWorX a)
|
, invitationInsertHook :: forall a. UserEmail -> 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
|
||||||
@ -402,7 +402,7 @@ invitationR' InvitationConfig{..} = liftHandler $ do
|
|||||||
return . Just $ SomeRoute HomeR
|
return . Just $ SomeRoute HomeR
|
||||||
Just (jData, formCtx) -> do
|
Just (jData, formCtx) -> do
|
||||||
let junction = review _InvitableJunction (invitee, fid, jData)
|
let junction = review _InvitableJunction (invitee, fid, jData)
|
||||||
mResult <- invitationInsertHook fEnt iData junction formCtx $ insertUniqueEntity junction
|
mResult <- invitationInsertHook itEmail fEnt iData junction formCtx $ insertUniqueEntity junction
|
||||||
case mResult of
|
case mResult of
|
||||||
Nothing -> invalidArgsI [MsgInvitationCollision]
|
Nothing -> invalidArgsI [MsgInvitationCollision]
|
||||||
Just res -> do
|
Just res -> do
|
||||||
|
|||||||
Reference in New Issue
Block a user