feat(submissions): warn about multiple submissions for same user

This commit is contained in:
Gregor Kleen 2021-03-19 16:09:15 +01:00
parent 9d1f1c6910
commit c19a00dcef
10 changed files with 57 additions and 12 deletions

View File

@ -403,6 +403,9 @@ input[type="button"].btn-info:not(.btn-link):hover,
font-weight: 600 font-weight: 600
color: var(--color-fontsec) color: var(--color-fontsec)
.table__td--tooltip
width: 2em
.table__td .table__td
font-size: 16px font-size: 16px
color: var(--color-font) color: var(--color-font)

View File

@ -404,6 +404,8 @@ SubmissionFilesCorrected: Abgegebene & Korrigierte Dateien
RatingUpdatedFiles: Bei der Korrektur wurden Dateien angepasst oder hinzugefügt RatingUpdatedFiles: Bei der Korrektur wurden Dateien angepasst oder hinzugefügt
SubmissionFilesUnchanged: Abgabedateien beibehalten SubmissionFilesUnchanged: Abgabedateien beibehalten
SubmissionFilesUnchangedTip: Sollen die bestehenden Abgabedateien beim Ersetzen der Abgabe unverändert übernommen werden? SubmissionFilesUnchangedTip: Sollen die bestehenden Abgabedateien beim Ersetzen der Abgabe unverändert übernommen werden?
SubmissionUserDuplicateWarning: Dieser Teilnehmende ist bereits an einer anderen Abgabe beteiligt
SubmissionSomeUsersDuplicateWarning: Manche Abgebende sind auch an einer anderen Abgabe beteiligt
SubmissionsDeleteQuestion n@Int: Wollen Sie #{pluralDE n "die unten aufgeführte Abgabe" "die unten aufgeführten Abgaben"} wirklich löschen? SubmissionsDeleteQuestion n@Int: Wollen Sie #{pluralDE n "die unten aufgeführte Abgabe" "die unten aufgeführten Abgaben"} wirklich löschen?
SubmissionsDeleted n@Int: #{pluralDE n "Abgabe gelöscht" "Abgaben gelöscht"} SubmissionsDeleted n@Int: #{pluralDE n "Abgabe gelöscht" "Abgaben gelöscht"}

View File

@ -402,6 +402,8 @@ SubmissionFilesCorrected: Submitted & Corrected files
RatingUpdatedFiles: During correction files were added or changed RatingUpdatedFiles: During correction files were added or changed
SubmissionFilesUnchanged: Keep submission files SubmissionFilesUnchanged: Keep submission files
SubmissionFilesUnchangedTip: Should the existing submission files be retained unchanged while replacing the submission? SubmissionFilesUnchangedTip: Should the existing submission files be retained unchanged while replacing the submission?
SubmissionUserDuplicateWarning: This participant is already a submittor for a different submission
SubmissionSomeUsersDuplicateWarning: Some submittors are also submittors for a different submission
SubmissionsDeleteQuestion n: Do you really want to delete the #{pluralEN n "submission" "submissions"} mentioned below? SubmissionsDeleteQuestion n: Do you really want to delete the #{pluralEN n "submission" "submissions"} mentioned below?
SubmissionsDeleted n: #{pluralEN n "Submission" "Submissions"} deleted SubmissionsDeleted n: #{pluralEN n "Submission" "Submissions"} deleted

View File

@ -32,8 +32,8 @@ import Handler.Submission.SubmissionUserInvite
import qualified Data.Conduit.Combinators as C import qualified Data.Conduit.Combinators as C
makeSubmissionForm :: CourseId -> Maybe SubmissionId -> UploadMode -> SheetGroup -> Maybe FileUploads -> Bool -> Set (Either UserEmail UserId) -> Form (Maybe FileUploads, Set (Either UserEmail UserId)) makeSubmissionForm :: CourseId -> SheetId -> Maybe SubmissionId -> UploadMode -> SheetGroup -> Maybe FileUploads -> Bool -> Set (Either UserEmail UserId) -> Form (Maybe FileUploads, Set (Either UserEmail UserId))
makeSubmissionForm cid msmid uploadMode grouping mPrev isLecturer prefillUsers = identifyForm FIDsubmission . renderAForm FormStandard $ (,) makeSubmissionForm cid shid msmid uploadMode grouping mPrev isLecturer prefillUsers = identifyForm FIDsubmission . renderAForm FormStandard $ (,)
<$> uploadForm <$> uploadForm
<*> wFormToAForm submittorsForm' <*> wFormToAForm submittorsForm'
where where
@ -51,7 +51,17 @@ makeSubmissionForm cid msmid uploadMode grouping mPrev isLecturer prefillUsers =
| otherwise -> MsgEmailInvitationWarningPrevCoSubmittors | otherwise -> MsgEmailInvitationWarningPrevCoSubmittors
$(widgetFile "widgets/massinput/submissionUsers/cellInvitation") $(widgetFile "widgets/massinput/submissionUsers/cellInvitation")
miCell' csrf (Right uid) = do miCell' csrf (Right uid) = do
User{..} <- liftHandler . runDB $ getJust uid (User{..}, hasSubmitted) <- liftHandler . runDB $ do
user <- getJust uid
hasSubmitted <- E.selectExists . E.from $ \(submissionUser `E.InnerJoin` submission) -> do
E.on $ submissionUser E.^. SubmissionUserSubmission E.==. submission E.^. SubmissionId
E.where_ $ submissionUser E.^. SubmissionUserUser E.==. E.val uid
E.&&. submission E.^. SubmissionSheet E.==. E.val shid
whenIsJust msmid $ \smid ->
E.where_ $ submission E.^. SubmissionId E.!=. E.val smid
return (user, hasSubmitted)
knownWarning <- runMaybeT $
guardOnM hasSubmitted $ messageIconI Error IconSubmissionUserDuplicate MsgSubmissionUserDuplicateWarning
$(widgetFile "widgets/massinput/submissionUsers/cellKnown") $(widgetFile "widgets/massinput/submissionUsers/cellKnown")
miLayout :: ListLength miLayout :: ListLength
@ -319,9 +329,9 @@ submissionHelper tid ssh csh shn mcid = do
-- @submissionModeUser == Nothing@ below iff we are currently serving a user with elevated rights (lecturer, admin, ...) -- @submissionModeUser == Nothing@ below iff we are currently serving a user with elevated rights (lecturer, admin, ...)
-- Therefore we do not restrict upload behaviour in any way in that case -- Therefore we do not restrict upload behaviour in any way in that case
((res,formWidget'), formEnctype) <- do ((res,formWidget'), formEnctype) <- do
(Entity _ Sheet{..}, buddies, _, _, isLecturer, isOwner, _, _) <- runDB getSheetInfo (Entity shid Sheet{..}, buddies, _, _, isLecturer, isOwner, _, _) <- runDB getSheetInfo
let mPrevUploads = msmid <&> \smid -> runDBSource $ selectSource [SubmissionFileSubmission ==. smid, SubmissionFileIsUpdate ==. False] [Asc SubmissionFileTitle] .| C.map (view $ _FileReference . _1) let mPrevUploads = msmid <&> \smid -> runDBSource $ selectSource [SubmissionFileSubmission ==. smid, SubmissionFileIsUpdate ==. False] [Asc SubmissionFileTitle] .| C.map (view $ _FileReference . _1)
runFormPost . makeSubmissionForm sheetCourse msmid (fromMaybe (UploadAny True Nothing True) . submissionModeUser $ sheetSubmissionMode) sheetGrouping mPrevUploads isLecturer $ bool id (maybe id (Set.insert . Right) muid) isOwner buddies runFormPost . makeSubmissionForm sheetCourse shid msmid (fromMaybe (UploadAny True Nothing True) . submissionModeUser $ sheetSubmissionMode) sheetGrouping mPrevUploads isLecturer $ bool id (maybe id (Set.insert . Right) muid) isOwner buddies
let formWidget = wrapForm' BtnHandIn formWidget' def let formWidget = wrapForm' BtnHandIn formWidget' def
{ formAction = Just $ SomeRoute actionUrl { formAction = Just $ SomeRoute actionUrl
, formEncoding = formEnctype , formEncoding = formEnctype
@ -360,6 +370,7 @@ submissionHelper tid ssh csh shn mcid = do
(FormFailure failmsgs) -> return $ FormFailure failmsgs (FormFailure failmsgs) -> return $ FormFailure failmsgs
(FormSuccess res'@(_, groupMembers)) (FormSuccess res'@(_, groupMembers))
| groupMembers == subUsersOld -> return $ FormSuccess res' | groupMembers == subUsersOld -> return $ FormSuccess res'
| isLecturer -> return $ FormSuccess res'
| Arbitrary{..} <- sheetGrouping -> do -- Validate AdHoc Group Members | Arbitrary{..} <- sheetGrouping -> do -- Validate AdHoc Group Members
let (gEMails, gIds) = partitionEithers $ Set.toList groupMembers let (gEMails, gIds) = partitionEithers $ Set.toList groupMembers
prep :: [(E.Value UserEmail, (E.Value UserId, E.Value Bool, E.Value Bool))] -> Map UserEmail (Maybe (UserId, Bool, Bool)) prep :: [(E.Value UserEmail, (E.Value UserId, E.Value Bool, E.Value Bool))] -> Map UserEmail (Maybe (UserId, Bool, Bool))
@ -486,7 +497,7 @@ submissionHelper tid ssh csh shn mcid = do
| otherwise -> redirect $ CSheetR tid ssh csh shn SShowR | otherwise -> redirect $ CSheetR tid ssh csh shn SShowR
Nothing -> return () Nothing -> return ()
(Entity _ Sheet{..}, _, lastEdits, maySubmit, _, _, msubmission, corrector) <- runDB getSheetInfo (Entity shid Sheet{..}, _, lastEdits, maySubmit, _, _, msubmission, corrector) <- runDB getSheetInfo
(showCorrection, correctionInvisible) <- fmap (fromMaybe (False, Nothing)) . for ((,) <$> mcid <*> (Entity <$> msmid <*> msubmission)) $ \(cid, subEnt) -> runDB $ do (showCorrection, correctionInvisible) <- fmap (fromMaybe (False, Nothing)) . for ((,) <$> mcid <*> (Entity <$> msmid <*> msubmission)) $ \(cid, subEnt) -> runDB $ do
showCorrection <- hasReadAccessTo $ CSubmissionR tid ssh csh shn cid CorrectionR showCorrection <- hasReadAccessTo $ CSubmissionR tid ssh csh shn cid CorrectionR
@ -565,6 +576,22 @@ submissionHelper tid ssh csh shn mcid = do
sheetTypeDesc <- liftHandler . runDB $ sheetTypeDescription sheetCourse sheetType sheetTypeDesc <- liftHandler . runDB $ sheetTypeDescription sheetCourse sheetType
multipleSubmissionWarnWidget <- runDB . runMaybeT $ do
subId <- hoistMaybe msmid
cID <- hoistMaybe mcid
guardM . lift $ orM
[ hasWriteAccessTo $ CSubmissionR tid ssh csh shn cID SubDelR
, hasWriteAccessTo $ CSubmissionR tid ssh csh shn cID SubShowR
]
guardM . lift . E.selectExists . E.from $ \(submissionUser `E.InnerJoin` (otherSubmissionUser `E.InnerJoin` submission)) -> do
E.on $ otherSubmissionUser E.^. SubmissionUserSubmission E.==. submission E.^. SubmissionId
E.on $ submissionUser E.^. SubmissionUserSubmission E.!=. otherSubmissionUser E.^. SubmissionUserSubmission
E.&&. submissionUser E.^. SubmissionUserUser E.==. otherSubmissionUser E.^. SubmissionUserUser
E.where_ $ submission E.^. SubmissionSheet E.==. E.val shid
E.&&. submission E.^. SubmissionId E.!=. E.val subId
E.&&. submissionUser E.^. SubmissionUserSubmission E.==. E.val subId
return $ notification NotificationBroad =<< messageIconI Warning IconSubmissionUserDuplicate MsgSubmissionSomeUsersDuplicateWarning
defaultLayout $ do defaultLayout $ do
setTitleI $ MsgSubmissionEditHead tid ssh csh shn setTitleI $ MsgSubmissionEditHead tid ssh csh shn
(urlArchive, urlOriginal) <- fmap ((,) <$> preview (_Just . _1) <*> preview (_Just . _2)) . for mcid $ \cID (urlArchive, urlOriginal) <- fmap ((,) <$> preview (_Just . _1) <*> preview (_Just . _2)) . for mcid $ \cID

View File

@ -92,6 +92,7 @@ data Icon
| IconPersonalIdentification | IconPersonalIdentification
| IconMenuWorkflows | IconMenuWorkflows
| IconVideo | IconVideo
| IconSubmissionUserDuplicate
deriving (Eq, Ord, Enum, Bounded, Show, Read, Generic, Typeable) deriving (Eq, Ord, Enum, Bounded, Show, Read, Generic, Typeable)
iconText :: Icon -> Text iconText :: Icon -> Text
@ -164,6 +165,7 @@ iconText = \case
IconPersonalIdentification -> "id-card" IconPersonalIdentification -> "id-card"
IconMenuWorkflows -> "project-diagram" IconMenuWorkflows -> "project-diagram"
IconVideo -> "video" IconVideo -> "video"
IconSubmissionUserDuplicate -> "copy"
instance Universe Icon instance Universe Icon
instance Finite Icon instance Finite Icon

View File

@ -8,6 +8,8 @@ $if is _Just mcid
^{warning} ^{warning}
^{wdgt} ^{wdgt}
^{maybeVoid multipleSubmissionWarnWidget}
<section> <section>
$case sheetSubmissionMode $case sheetSubmissionMode

View File

@ -2,5 +2,5 @@ $newline never
<td> <td>
<span .email> <span .email>
#{email} #{email}
<td> <td .table__td--tooltip>
^{messageTooltip invWarnMsg} ^{messageTooltip invWarnMsg}

View File

@ -2,5 +2,5 @@
<td> <td>
<span .email> <span .email>
#{email} #{email}
<td> <td .table__td--tooltip>
^{messageTooltip invWarnMsg} ^{messageTooltip invWarnMsg}

View File

@ -3,5 +3,5 @@
#{csrf} #{csrf}
<span .email> <span .email>
#{email} #{email}
<td> <td .table__td--tooltip>
^{messageTooltip invWarnMsg} ^{messageTooltip invWarnMsg}

View File

@ -1,4 +1,11 @@
$newline never $newline never
<td colspan=2> $maybe wrn <- knownWarning
#{csrf} <td>
^{nameEmailWidget userEmail userDisplayName userSurname} #{csrf}
^{nameEmailWidget userEmail userDisplayName userSurname}
<td .table__td--tooltip>
^{messageTooltip wrn}
$nothing
<td colspan=2>
#{csrf}
^{nameEmailWidget userEmail userDisplayName userSurname}