feat(corrections): better highlight corrected files

Fixes #602
This commit is contained in:
Gregor Kleen 2020-06-27 15:39:16 +02:00
parent b0a81b2798
commit 46ce477235
7 changed files with 63 additions and 17 deletions

View File

@ -361,12 +361,15 @@ SubmissionMembers: Abgebende
SubmissionMember: Abgebende(r) SubmissionMember: Abgebende(r)
CosubmittorTip: Einladungen per E-Mail erhalten genau jene Adressen, für die nicht gesichert werden kann, dass sie mit der dahinter stehenden Person schon einmal für diesen Kurs abgegeben haben. Wenn eine angegebene Adresse einer Person zugeordnet werden kann, mit der Sie in diesem Kurs schon einmal zusammen abgegeben haben, wird der Name der Person angezeigt und die Abgabe erfolgt sofort auch im Namen jener Person. CosubmittorTip: Einladungen per E-Mail erhalten genau jene Adressen, für die nicht gesichert werden kann, dass sie mit der dahinter stehenden Person schon einmal für diesen Kurs abgegeben haben. Wenn eine angegebene Adresse einer Person zugeordnet werden kann, mit der Sie in diesem Kurs schon einmal zusammen abgegeben haben, wird der Name der Person angezeigt und die Abgabe erfolgt sofort auch im Namen jener Person.
SubmissionArchive: Zip-Archiv der Abgabedatei(en) SubmissionArchive: Zip-Archiv der Abgabedatei(en)
SubmissionArchiveCorrected: Zip-Archiv der Abgabedatei(en) inkl. Korrekturen
SubmissionFile: Datei zur Abgabe SubmissionFile: Datei zur Abgabe
SubmissionFiles: Abgegebene Dateien SubmissionFiles: Abgegebene Dateien
SubmissionAlreadyExistsFor email@UserEmail: #{email} hat bereits eine Abgabe zu diesem Übungsblatt. SubmissionAlreadyExistsFor email@UserEmail: #{email} hat bereits eine Abgabe zu diesem Übungsblatt.
SubmissionUsersEmpty: Es kann keine Abgabe ohne Abgebende erstellt werden SubmissionUsersEmpty: Es kann keine Abgabe ohne Abgebende erstellt werden
SubmissionUserAlreadyAdded: Dieser Nutzer ist bereits als Mitabgebende(r) eingetragen SubmissionUserAlreadyAdded: Dieser Nutzer ist bereits als Mitabgebende(r) eingetragen
NoOpenSubmissions: Keine unkorrigierten Abgaben vorhanden NoOpenSubmissions: Keine unkorrigierten Abgaben vorhanden
SubmissionFilesCorrected: Abgegebene & Korrigierte Dateien
RatingUpdatedFiles: Bei der Korrektur wurden Dateien angepasst oder hinzugefügt
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

@ -360,12 +360,15 @@ SubmissionMembers: Submittors
SubmissionMember: Submittor SubmissionMember: Submittor
CosubmittorTip: Invitations are sent via email to exactly those addresses for which it cannot be determined, that you have already submitted for this course with the associated person, at least once. If one of the specified addresses can be matched to a person with whom you have submitted at least once for this course already, the name of that person will be shown and the submission will immediately be made in their name as well. CosubmittorTip: Invitations are sent via email to exactly those addresses for which it cannot be determined, that you have already submitted for this course with the associated person, at least once. If one of the specified addresses can be matched to a person with whom you have submitted at least once for this course already, the name of that person will be shown and the submission will immediately be made in their name as well.
SubmissionArchive: Zip-archive of submission files SubmissionArchive: Zip-archive of submission files
SubmissionArchiveCorrected: Zip-archive of submission files including corrections
SubmissionFile: Submission file SubmissionFile: Submission file
SubmissionFiles: Submitted files SubmissionFiles: Submitted files
SubmissionAlreadyExistsFor email: #{email} already has a submission for this sheet. SubmissionAlreadyExistsFor email: #{email} already has a submission for this sheet.
SubmissionUsersEmpty: Submissions may not be created without submittors. SubmissionUsersEmpty: Submissions may not be created without submittors.
SubmissionUserAlreadyAdded: This user is already configured as a submittor SubmissionUserAlreadyAdded: This user is already configured as a submittor
NoOpenSubmissions: No open submissions exist NoOpenSubmissions: No open submissions exist
SubmissionFilesCorrected: Submitted & Corrected files
RatingUpdatedFiles: During correction files were added or changed
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

@ -4048,7 +4048,7 @@ pageActions (CSubmissionR tid ssh csh shn cid SubShowR) = return
{ navLink = NavLink { navLink = NavLink
{ navLabel = MsgMenuCorrection { navLabel = MsgMenuCorrection
, navRoute = CSubmissionR tid ssh csh shn cid CorrectionR , navRoute = CSubmissionR tid ssh csh shn cid CorrectionR
, navAccess' = return True , navAccess' = hasWriteAccessTo $ CSubmissionR tid ssh csh shn cid CorrectionR
, navType = NavTypeLink { navModal = False } , navType = NavTypeLink { navModal = False }
, navQuick' = mempty , navQuick' = mempty
, navForceActive = False , navForceActive = False

View File

@ -15,6 +15,7 @@ import qualified Data.Text as Text
import qualified Control.Monad.State.Class as State import qualified Control.Monad.State.Class as State
import qualified Database.Esqueleto as E import qualified Database.Esqueleto as E
import qualified Database.Esqueleto.Utils as E
import qualified Data.Conduit.List as C import qualified Data.Conduit.List as C
@ -29,7 +30,16 @@ correctionData tid ssh csh shn sub = E.select . E.from $ \((course `E.InnerJoin`
E.&&. course E.^. CourseShorthand E.==. E.val csh E.&&. course E.^. CourseShorthand E.==. E.val csh
E.&&. sheet E.^. SheetName E.==. E.val shn E.&&. sheet E.^. SheetName E.==. E.val shn
E.&&. submission E.^. SubmissionId E.==. E.val sub E.&&. submission E.^. SubmissionId E.==. E.val sub
return (course, sheet, submission, corrector) let filesCorrected = E.exists . E.from $ \((f1 `E.InnerJoin` sFile1) `E.LeftOuterJoin` (f2 `E.InnerJoin` sFile2)) -> do
E.on $ f2 E.?. FileId E.==. sFile2 E.?. SubmissionFileFile
E.on $ E.just (f1 E.^. FileTitle) E.==. f2 E.?. FileTitle
E.&&. E.just (sFile1 E.^. SubmissionFileSubmission) E.==. sFile2 E.?. SubmissionFileSubmission
-- E.&&. f1 E.^. FileContent E.!=. E.joinV (f2 E.?. FileContent)
E.&&. sFile1 E.^. SubmissionFileIsUpdate E.&&. E.maybe E.false E.not_ (sFile2 E.?. SubmissionFileIsUpdate)
E.on $ f1 E.^. FileId E.==. sFile1 E.^. SubmissionFileFile
E.where_ $ sFile1 E.^. SubmissionFileSubmission E.==. submission E.^. SubmissionId
E.&&. sFile2 E.?. SubmissionFileSubmission E.==. E.just (submission E.^. SubmissionId)
return (course, sheet, submission, corrector, filesCorrected)
getCorrectionR, getCorrectionUserR, postCorrectionR :: TermId -> SchoolId -> CourseShorthand -> SheetName -> CryptoFileNameSubmission -> Handler Html getCorrectionR, getCorrectionUserR, postCorrectionR :: TermId -> SchoolId -> CourseShorthand -> SheetName -> CryptoFileNameSubmission -> Handler Html
getCorrectionR tid ssh csh shn cid = do getCorrectionR tid ssh csh shn cid = do
@ -44,7 +54,7 @@ postCorrectionR tid ssh csh shn cid = do
MsgRenderer mr <- getMsgRenderer MsgRenderer mr <- getMsgRenderer
case results of case results of
[(Entity cId Course{..}, Entity shId Sheet{..}, Entity _ subm@Submission{..}, corrector)] -> do [(Entity cId Course{..}, Entity shId Sheet{..}, Entity _ subm@Submission{..}, corrector, E.Value filesCorrected)] -> do
let ratingComment = fmap Text.strip submissionRatingComment >>= (\c -> c <$ guard (not $ null c)) let ratingComment = fmap Text.strip submissionRatingComment >>= (\c -> c <$ guard (not $ null c))
pointsForm = case sheetType of pointsForm = case sheetType of
NotGraded NotGraded
@ -144,12 +154,14 @@ postCorrectionR tid ssh csh shn cid = do
getCorrectionUserR tid ssh csh shn cid = do getCorrectionUserR tid ssh csh shn cid = do
sub <- decrypt cid sub <- decrypt cid
results <- runDB $ correctionData tid ssh csh shn sub results <- runDB $ correctionData tid ssh csh shn sub
case results of case results of
[(Entity _ Course{..}, Entity _ Sheet{..}, Entity _ Submission{..}, corrector@(Just _))] -> [(Entity _ Course{..}, Entity _ Sheet{..}, Entity _ Submission{..}, corrector@(Just _), E.Value filesCorrected)] ->
let ratingComment = fmap Text.strip submissionRatingComment >>= (\c -> c <$ guard (not $ null c)) let ratingComment = assertM (not . null) $ Text.strip <$> submissionRatingComment
in defaultLayout $(widgetFile "correction-user") in defaultLayout $(widgetFile "correction-user")
_ -> notFound _ -> notFound

View File

@ -15,6 +15,7 @@ import Handler.Utils.Invitations
import Data.Maybe (fromJust) import Data.Maybe (fromJust)
import qualified Database.Esqueleto as E import qualified Database.Esqueleto as E
import qualified Database.Esqueleto.Utils as E
import qualified Database.Esqueleto.Internal.Sql as E (unsafeSqlFunction) import qualified Database.Esqueleto.Internal.Sql as E (unsafeSqlFunction)
import qualified Data.Conduit.Combinators as Conduit import qualified Data.Conduit.Combinators as Conduit
@ -476,10 +477,12 @@ 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 ()
showCorrection <- fmap (fromMaybe False) . for mcid $ \cid -> hasReadAccessTo $ CSubmissionR tid ssh csh shn cid CorrectionR
-- Maybe construct a table to display uploaded archive files -- Maybe construct a table to display uploaded archive files
let colonnadeFiles :: _ -> Colonnade Sortable _ (DBCell (HandlerFor UniWorX) ()) let colonnadeFiles :: _ -> Colonnade Sortable _ (DBCell (HandlerFor UniWorX) ())
colonnadeFiles cid = mconcat colonnadeFiles cid = mconcat $ catMaybes
[ sortable (Just "path") (i18nCell MsgFileTitle) $ \(coalesce -> (mOrig, mCorr)) -> let [ Just . sortable (Just "path") (i18nCell MsgFileTitle) $ \(coalesce -> (mOrig, mCorr)) -> let
Just fileTitle' = fileTitle . entityVal . snd <$> (mOrig <|> mCorr) Just fileTitle' = fileTitle . entityVal . snd <$> (mOrig <|> mCorr)
origIsFile = fmap (isJust . fileContent . entityVal . snd) mOrig origIsFile = fmap (isJust . fileContent . entityVal . snd) mOrig
corrIsFile = fmap (isJust . fileContent . entityVal . snd) mCorr corrIsFile = fmap (isJust . fileContent . entityVal . snd) mCorr
@ -488,13 +491,14 @@ submissionHelper tid ssh csh shn mcid = do
| Just True <- origIsFile -> anchorCell (CSubmissionR tid ssh csh shn cid $ SubDownloadR SubmissionOriginal fileTitle') | Just True <- origIsFile -> anchorCell (CSubmissionR tid ssh csh shn cid $ SubDownloadR SubmissionOriginal fileTitle')
[whamlet|#{fileTitle'}|] [whamlet|#{fileTitle'}|]
| otherwise -> textCell $ bool (<> "/") id isFile fileTitle' | otherwise -> textCell $ bool (<> "/") id isFile fileTitle'
, sortable (toNothing "state") (i18nCell MsgCorState) $ \(coalesce -> (_, mCorr)) -> case mCorr of , guardOn showCorrection . sortable (toNothing "state") (i18nCell MsgCorState) $ \(coalesce -> (_, mCorr)) -> case mCorr of
Nothing -> cell mempty Nothing -> cell mempty
Just (_, Entity _ File{..}) Just (_, Entity _ File{..})
| isJust fileContent -> anchorCell (CSubmissionR tid ssh csh shn cid $ SubDownloadR SubmissionCorrected fileTitle) | isJust fileContent ->
[whamlet|_{MsgFileCorrected}|] anchorCell (CSubmissionR tid ssh csh shn cid $ SubDownloadR SubmissionCorrected fileTitle)
[whamlet|_{MsgFileCorrected}|]
| otherwise -> i18nCell MsgCorrected | otherwise -> i18nCell MsgCorrected
, sortable (Just "time") (i18nCell MsgFileModified) $ \(coalesce -> (mOrig, mCorr)) -> let , Just . sortable (Just "time") (i18nCell MsgFileModified) $ \(coalesce -> (mOrig, mCorr)) -> let
origTime = fileModified . entityVal . snd <$> mOrig origTime = fileModified . entityVal . snd <$> mOrig
corrTime = fileModified . entityVal . snd <$> mCorr corrTime = fileModified . entityVal . snd <$> mCorr
Just fileTime = (max <$> origTime <*> corrTime) <|> origTime <|> corrTime Just fileTime = (max <$> origTime <*> corrTime) <|> origTime <|> corrTime
@ -541,10 +545,21 @@ submissionHelper tid ssh csh shn mcid = do
mFileTable <- traverse (runDB . dbTableWidget' def) . fmap smid2ArchiveTable $ (,) <$> msmid <*> mcid mFileTable <- traverse (runDB . dbTableWidget' def) . fmap smid2ArchiveTable $ (,) <$> msmid <*> mcid
showCorrection <- fmap (fromMaybe False) . for mcid $ \cid -> hasReadAccessTo $ CSubmissionR tid ssh csh shn cid CorrectionR filesCorrected <- fmap (fromMaybe False) . for msmid $ \subId -> runDB . E.selectExists . E.from $ \((f1 `E.InnerJoin` sFile1) `E.LeftOuterJoin` (f2 `E.InnerJoin` sFile2)) -> do
E.on $ f2 E.?. FileId E.==. sFile2 E.?. SubmissionFileFile
E.on $ E.just (f1 E.^. FileTitle) E.==. f2 E.?. FileTitle
E.&&. E.just (sFile1 E.^. SubmissionFileSubmission) E.==. sFile2 E.?. SubmissionFileSubmission
-- E.&&. f1 E.^. FileContent E.!=. E.joinV (f2 E.?. FileContent)
E.&&. sFile1 E.^. SubmissionFileIsUpdate E.&&. E.maybe E.false E.not_ (sFile2 E.?. SubmissionFileIsUpdate)
E.on $ f1 E.^. FileId E.==. sFile1 E.^. SubmissionFileFile
E.where_ $ sFile1 E.^. SubmissionFileSubmission E.==. E.val subId
E.where_ $ sFile2 E.?. SubmissionFileSubmission E.==. E.just (E.val subId)
let correctionWdgt = guardOnM (showCorrection && maybe False submissionRatingDone msubmission) ((,) <$> msubmission <*> mcid) <&> \(Submission{..}, cid) -> let correctionWdgt = guardOnM (showCorrection && maybe False submissionRatingDone msubmission) ((,) <$> msubmission <*> mcid) <&> \(Submission{..}, cid) ->
let ratingComment = assertM (not . null) $ Text.strip <$> submissionRatingComment let ratingComment = assertM (not . null) $ Text.strip <$> submissionRatingComment
courseTerm = tid
courseSchool = ssh
courseShorthand = csh
in $(widgetFile "correction-user") in $(widgetFile "correction-user")

View File

@ -40,6 +40,13 @@
_{MsgNotPassed} _{MsgNotPassed}
$of PassAlways $of PassAlways
$if filesCorrected
<tr .table__row>
<th .table__th>_{MsgRatingFiles}
<td .table__td>
<a href=@{CSubmissionR courseTerm courseSchool courseShorthand sheetName cid $ SubArchiveR SubmissionCorrected}>
_{MsgRatingUpdatedFiles}
$maybe comment <- ratingComment $maybe comment <- ratingComment
<tr .table__row> <tr .table__row>
<th .table__th>_{MsgRatingComment} <th .table__th>_{MsgRatingComment}

View File

@ -12,12 +12,18 @@ $maybe cID <- mcid
_{MsgSubmissionNoUploadExpected} _{MsgSubmissionNoUploadExpected}
$of _ $of _
<h2> <h2>
_{MsgSubmissionFiles} $if filesCorrected
_{MsgSubmissionFilesCorrected}
$else
_{MsgSubmissionFiles}
<p> <p>
<a href=@{urlArchive cID}>_{MsgSubmissionArchive} $if showCorrection
\ ( <a href=@{urlArchive cID}>_{MsgSubmissionArchiveCorrected}
<a href=@{urlOriginal cID}>_{MsgSubmissionOriginal} \ (
) <a href=@{urlOriginal cID}>_{MsgSubmissionOriginal}
)
$else
<a href=@{urlOriginal cID}>_{MsgSubmissionArchive}
$maybe fileTable <- mFileTable $maybe fileTable <- mFileTable
^{fileTable} ^{fileTable}