Single submission assign corrector
This commit is contained in:
parent
225bd9b01d
commit
673d98ff91
3
.vscode/tasks.json
vendored
3
.vscode/tasks.json
vendored
@ -28,7 +28,8 @@
|
|||||||
"focus": false,
|
"focus": false,
|
||||||
"panel": "dedicated",
|
"panel": "dedicated",
|
||||||
"showReuseMessage": false
|
"showReuseMessage": false
|
||||||
}
|
},
|
||||||
|
"problemMatcher": []
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"label": "test",
|
"label": "test",
|
||||||
|
|||||||
@ -142,6 +142,8 @@ SubmissionGroupName: Gruppenname
|
|||||||
CorrectionsTitle: Zugewiesene Korrekturen
|
CorrectionsTitle: Zugewiesene Korrekturen
|
||||||
CourseCorrectionsTitle: Korrekturen für diesen Kurs
|
CourseCorrectionsTitle: Korrekturen für diesen Kurs
|
||||||
CorrectorsHead sheetName@SheetName: Korrektoren für #{sheetName}
|
CorrectorsHead sheetName@SheetName: Korrektoren für #{sheetName}
|
||||||
|
CorrectorAssignTitle: Korrektor zuweisen
|
||||||
|
|
||||||
|
|
||||||
Unauthorized: Sie haben hierfür keine explizite Berechtigung.
|
Unauthorized: Sie haben hierfür keine explizite Berechtigung.
|
||||||
UnauthorizedAnd l@Text r@Text: (#{l} UND #{r})
|
UnauthorizedAnd l@Text r@Text: (#{l} UND #{r})
|
||||||
@ -189,6 +191,7 @@ CorByProportionExcludingTutorial proportion@Rational: #{display proportion} Ante
|
|||||||
|
|
||||||
DeleteRow: Zeile entfernen
|
DeleteRow: Zeile entfernen
|
||||||
ProportionNegative: Anteile dürfen nicht negativ sein
|
ProportionNegative: Anteile dürfen nicht negativ sein
|
||||||
|
CorrectorUpdated: Korrektor erfolgreich aktualisiert
|
||||||
CorrectorsUpdated: Korrektoren erfolgreich aktualisiert
|
CorrectorsUpdated: Korrektoren erfolgreich aktualisiert
|
||||||
CorrectorsPlaceholder: Korrektoren...
|
CorrectorsPlaceholder: Korrektoren...
|
||||||
CorrectorsDefaulted: Korrektoren-Liste wurde aus bisherigen Übungsblättern diesen Kurses generiert. Es sind keine Daten gespeichert.
|
CorrectorsDefaulted: Korrektoren-Liste wurde aus bisherigen Übungsblättern diesen Kurses generiert. Es sind keine Daten gespeichert.
|
||||||
@ -258,7 +261,7 @@ RatingDone: Bewertung fertiggestellt
|
|||||||
RatingPercent: Erreicht
|
RatingPercent: Erreicht
|
||||||
RatingFiles: Korrigierte Dateien
|
RatingFiles: Korrigierte Dateien
|
||||||
PointsNotPositive: Punktzahl darf nicht negativ sein
|
PointsNotPositive: Punktzahl darf nicht negativ sein
|
||||||
PointsTooHigh maxPoints@Points: Punktzahl darf nicht höher als #{tshow maxPoints} sein
|
PointsTooHigh maxPoints@Points: Punktzahl darf nicht höher als #{tshow maxPoints} sein
|
||||||
RatingPointsDone: Abgabe zählt als korrigiert, gdw. Punktezahl gesetzt ist
|
RatingPointsDone: Abgabe zählt als korrigiert, gdw. Punktezahl gesetzt ist
|
||||||
ColumnRatingPointsDone: Punktzahl/Abgeschlossen
|
ColumnRatingPointsDone: Punktzahl/Abgeschlossen
|
||||||
Pseudonyms: Pseudonyme
|
Pseudonyms: Pseudonyme
|
||||||
@ -366,7 +369,7 @@ SheetGrading: Bewertung
|
|||||||
SheetGradingPoints maxPoints@Points: #{tshow maxPoints} Punkte
|
SheetGradingPoints maxPoints@Points: #{tshow maxPoints} Punkte
|
||||||
SheetGradingPassPoints maxPoints@Points passingPoints@Points: Bestanden ab #{tshow passingPoints} von #{tshow maxPoints} Punkten
|
SheetGradingPassPoints maxPoints@Points passingPoints@Points: Bestanden ab #{tshow passingPoints} von #{tshow maxPoints} Punkten
|
||||||
SheetGradingPassBinary: Bestanden/Nicht Bestanden
|
SheetGradingPassBinary: Bestanden/Nicht Bestanden
|
||||||
SheetGradingInfo: "Bestanden nach Punkten" zählt sowohl zur maximal erreichbaren Gesamtpunktzahl also auch zur Anzahl der zu bestehenden Blätter.
|
SheetGradingInfo: "Bestanden nach Punkten" zählt sowohl zur maximal erreichbaren Gesamtpunktzahl also auch zur Anzahl der zu bestehenden Blätter.
|
||||||
|
|
||||||
SheetGradingPoints': Punkte
|
SheetGradingPoints': Punkte
|
||||||
SheetGradingPassPoints': Bestehen nach Punkten
|
SheetGradingPassPoints': Bestehen nach Punkten
|
||||||
@ -424,7 +427,7 @@ HelpUser: Meinen Benutzeraccount
|
|||||||
HelpAnonymous: Keine Antwort (Anonym)
|
HelpAnonymous: Keine Antwort (Anonym)
|
||||||
HelpEMail: E-Mail
|
HelpEMail: E-Mail
|
||||||
HelpRequest: Supportanfrage / Verbesserungsvorschlag
|
HelpRequest: Supportanfrage / Verbesserungsvorschlag
|
||||||
HelpProblemPage: Problematische Seite
|
HelpProblemPage: Problematische Seite
|
||||||
HelpIntroduction: Wenn Ihnen die Benutzung dieser Webseite Schwierigkeiten bereitet oder Sie einen verbesserbaren Umstand entdecken bitten wir Sie uns das zu melden, auch wenn Sie Ihr Problem bereits selbst lösen konnten. Wir passen die Seite ständig an und versuchen sie auch für zukünftige Benutzer so einsichtig wie möglich zu halten.
|
HelpIntroduction: Wenn Ihnen die Benutzung dieser Webseite Schwierigkeiten bereitet oder Sie einen verbesserbaren Umstand entdecken bitten wir Sie uns das zu melden, auch wenn Sie Ihr Problem bereits selbst lösen konnten. Wir passen die Seite ständig an und versuchen sie auch für zukünftige Benutzer so einsichtig wie möglich zu halten.
|
||||||
HelpSent: Ihre Supportanfrage wurde weitergeleitet.
|
HelpSent: Ihre Supportanfrage wurde weitergeleitet.
|
||||||
|
|
||||||
@ -484,6 +487,7 @@ ErrMsgCouldNotDecodeNonce: Konnte secretbox-nonce nicht dekodieren
|
|||||||
ErrMsgCouldNotOpenSecretbox: Konnte libsodium-secretbox nicht öffnen (Verschlüsselte Daten sind nicht authentisch)
|
ErrMsgCouldNotOpenSecretbox: Konnte libsodium-secretbox nicht öffnen (Verschlüsselte Daten sind nicht authentisch)
|
||||||
ErrMsgCouldNotDecodePlaintext utf8Err@Text: Konnte Klartext nicht UTF8-dekodieren: #{utf8Err}
|
ErrMsgCouldNotDecodePlaintext utf8Err@Text: Konnte Klartext nicht UTF8-dekodieren: #{utf8Err}
|
||||||
ErrMsgHeading: Fehlermeldung entschlüsseln
|
ErrMsgHeading: Fehlermeldung entschlüsseln
|
||||||
|
ErrorCryptoIdMismatch: Verschlüsselte Id der Abgabe passte nicht zu anderen Daten
|
||||||
|
|
||||||
InvalidRoute: Konnte URL nicht interpretieren
|
InvalidRoute: Konnte URL nicht interpretieren
|
||||||
|
|
||||||
|
|||||||
14
models
14
models
@ -15,7 +15,7 @@ User json
|
|||||||
notificationSettings NotificationSettings
|
notificationSettings NotificationSettings
|
||||||
UniqueAuthentication ident
|
UniqueAuthentication ident
|
||||||
UniqueEmail email
|
UniqueEmail email
|
||||||
deriving Show
|
deriving Show Eq
|
||||||
UserAdmin
|
UserAdmin
|
||||||
user UserId
|
user UserId
|
||||||
school SchoolId
|
school SchoolId
|
||||||
@ -46,9 +46,9 @@ Term json
|
|||||||
start Day -- TermKey :: TermIdentifier -> TermId
|
start Day -- TermKey :: TermIdentifier -> TermId
|
||||||
end Day
|
end Day
|
||||||
holidays [Day]
|
holidays [Day]
|
||||||
lectureStart Day
|
lectureStart Day
|
||||||
lectureEnd Day
|
lectureEnd Day
|
||||||
active Bool
|
active Bool
|
||||||
Primary name -- newtype Key Term = TermKey { unTermKey :: TermIdentifier }
|
Primary name -- newtype Key Term = TermKey { unTermKey :: TermIdentifier }
|
||||||
deriving Show -- type TermId = Key Term
|
deriving Show -- type TermId = Key Term
|
||||||
School json
|
School json
|
||||||
@ -57,7 +57,7 @@ School json
|
|||||||
UniqueSchool name
|
UniqueSchool name
|
||||||
UniqueSchoolShorthand shorthand -- required for Normalisation of CI Text
|
UniqueSchoolShorthand shorthand -- required for Normalisation of CI Text
|
||||||
Primary shorthand -- newtype Key School = SchoolKey { unSchoolKey :: SchoolShorthand }
|
Primary shorthand -- newtype Key School = SchoolKey { unSchoolKey :: SchoolShorthand }
|
||||||
deriving Eq
|
deriving Eq
|
||||||
DegreeCourse json
|
DegreeCourse json
|
||||||
course CourseId
|
course CourseId
|
||||||
degree StudyDegreeId
|
degree StudyDegreeId
|
||||||
@ -89,7 +89,7 @@ CourseFavourite
|
|||||||
course CourseId
|
course CourseId
|
||||||
UniqueCourseFavourite user course
|
UniqueCourseFavourite user course
|
||||||
deriving Show
|
deriving Show
|
||||||
Lecturer
|
Lecturer
|
||||||
user UserId
|
user UserId
|
||||||
course CourseId
|
course CourseId
|
||||||
UniqueLecturer user course
|
UniqueLecturer user course
|
||||||
@ -135,7 +135,7 @@ SheetFile
|
|||||||
file FileId
|
file FileId
|
||||||
type SheetFileType
|
type SheetFileType
|
||||||
UniqueSheetFile file sheet type
|
UniqueSheetFile file sheet type
|
||||||
File
|
File
|
||||||
title FilePath
|
title FilePath
|
||||||
content ByteString Maybe -- Nothing iff this is a directory
|
content ByteString Maybe -- Nothing iff this is a directory
|
||||||
modified UTCTime
|
modified UTCTime
|
||||||
|
|||||||
3
routes
3
routes
@ -23,7 +23,7 @@
|
|||||||
-- !isWrite -- only if it is write access (i.e. POST only) why needed???
|
-- !isWrite -- only if it is write access (i.e. POST only) why needed???
|
||||||
--
|
--
|
||||||
-- !deprecated -- like free, but logs and gives a warning; entirely disabled in production
|
-- !deprecated -- like free, but logs and gives a warning; entirely disabled in production
|
||||||
-- !development -- like free, but only for development builds
|
-- !development -- like free, but only for development builds
|
||||||
|
|
||||||
/static StaticR Static appStatic !free
|
/static StaticR Static appStatic !free
|
||||||
/auth AuthR Auth getAuth !free
|
/auth AuthR Auth getAuth !free
|
||||||
@ -79,6 +79,7 @@
|
|||||||
/sub/#CryptoFileNameSubmission SubmissionR !correctorANDisRead:
|
/sub/#CryptoFileNameSubmission SubmissionR !correctorANDisRead:
|
||||||
/ SubShowR GET POST !ownerANDtime !ownerANDisRead
|
/ SubShowR GET POST !ownerANDtime !ownerANDisRead
|
||||||
/archive/#{ZIPArchiveName SubmissionFileType} SubArchiveR GET !owner
|
/archive/#{ZIPArchiveName SubmissionFileType} SubArchiveR GET !owner
|
||||||
|
/assign SAssignR GET POST !lecturerANDtime
|
||||||
/correction CorrectionR GET POST !corrector !ownerANDisReadANDrated
|
/correction CorrectionR GET POST !corrector !ownerANDisReadANDrated
|
||||||
!/#SubmissionFileType/*FilePath SubDownloadR GET !owner
|
!/#SubmissionFileType/*FilePath SubDownloadR GET !owner
|
||||||
/correctors SCorrR GET POST
|
/correctors SCorrR GET POST
|
||||||
|
|||||||
@ -208,7 +208,7 @@ instance RenderMessage UniWorX (SheetType) where
|
|||||||
renderMessage foundation ls sheetType = case sheetType of
|
renderMessage foundation ls sheetType = case sheetType of
|
||||||
NotGraded -> mr $ SheetTypeHeader NotGraded
|
NotGraded -> mr $ SheetTypeHeader NotGraded
|
||||||
other -> mr (grading other) <> ", " <> mr (SheetTypeHeader other)
|
other -> mr (grading other) <> ", " <> mr (SheetTypeHeader other)
|
||||||
where
|
where
|
||||||
mr :: RenderMessage UniWorX msg => msg -> Text
|
mr :: RenderMessage UniWorX msg => msg -> Text
|
||||||
mr = renderMessage foundation ls
|
mr = renderMessage foundation ls
|
||||||
|
|
||||||
@ -432,12 +432,13 @@ knownTags = Map.fromList -- should not throw exceptions, i.e. no getBy404 or req
|
|||||||
guard visible
|
guard visible
|
||||||
|
|
||||||
case subRoute of
|
case subRoute of
|
||||||
SFileR SheetExercise _ -> guard $ sheetActiveFrom <= cTime
|
SFileR SheetExercise _ -> guard $ sheetActiveFrom <= cTime
|
||||||
SFileR SheetHint _ -> guard $ maybe False (<= cTime) sheetHintFrom
|
SFileR SheetHint _ -> guard $ maybe False (<= cTime) sheetHintFrom
|
||||||
SFileR SheetSolution _ -> guard $ maybe False (<= cTime) sheetSolutionFrom
|
SFileR SheetSolution _ -> guard $ maybe False (<= cTime) sheetSolutionFrom
|
||||||
SubmissionNewR -> guard active
|
SubmissionNewR -> guard active
|
||||||
SubmissionR _ _ -> guard active
|
SubmissionR _ SAssignR -> guard $ not active -- Correctors can only be assigned when the Sheet is inactive, since submissions are subject to change
|
||||||
_ -> return ()
|
SubmissionR _ _ -> guard active
|
||||||
|
_ -> return ()
|
||||||
|
|
||||||
return Authorized
|
return Authorized
|
||||||
|
|
||||||
@ -525,7 +526,7 @@ knownTags = Map.fromList -- should not throw exceptions, i.e. no getBy404 or req
|
|||||||
SystemMessage{..} <- MaybeT $ get smId
|
SystemMessage{..} <- MaybeT $ get smId
|
||||||
isAuthenticated <- isJust <$> liftHandlerT maybeAuthId
|
isAuthenticated <- isJust <$> liftHandlerT maybeAuthId
|
||||||
guard $ not systemMessageAuthenticatedOnly || isAuthenticated
|
guard $ not systemMessageAuthenticatedOnly || isAuthenticated
|
||||||
return Authorized
|
return Authorized
|
||||||
r -> $unsupportedAuthPredicate "authentication" r
|
r -> $unsupportedAuthPredicate "authentication" r
|
||||||
)
|
)
|
||||||
,("isRead", APHandler . const $ bool (return Authorized) (unauthorizedI MsgUnauthorizedWrite))
|
,("isRead", APHandler . const $ bool (return Authorized) (unauthorizedI MsgUnauthorizedWrite))
|
||||||
@ -601,7 +602,7 @@ instance Yesod UniWorX where
|
|||||||
cid <- MaybeT . getKeyBy $ TermSchoolCourseShort tid ssh csh
|
cid <- MaybeT . getKeyBy $ TermSchoolCourseShort tid ssh csh
|
||||||
user <- MaybeT $ get uid
|
user <- MaybeT $ get uid
|
||||||
let courseFavourite = CourseFavourite uid now cid
|
let courseFavourite = CourseFavourite uid now cid
|
||||||
|
|
||||||
$logDebugS "updateFavourites" [st|Updating/Inserting: #{tshow courseFavourite}|]
|
$logDebugS "updateFavourites" [st|Updating/Inserting: #{tshow courseFavourite}|]
|
||||||
-- update Favourites
|
-- update Favourites
|
||||||
void . lift $ upsertBy
|
void . lift $ upsertBy
|
||||||
@ -650,7 +651,7 @@ instance Yesod UniWorX where
|
|||||||
#{formatted}
|
#{formatted}
|
||||||
|]
|
|]
|
||||||
| otherwise -> plaintext
|
| otherwise -> plaintext
|
||||||
|
|
||||||
errPage = case err of
|
errPage = case err of
|
||||||
NotFound -> [whamlet|<p>_{MsgErrorResponseNotFound}|]
|
NotFound -> [whamlet|<p>_{MsgErrorResponseNotFound}|]
|
||||||
InternalError err' -> encrypted err' [whamlet|<p .errMsg>#{err'}|]
|
InternalError err' -> encrypted err' [whamlet|<p .errMsg>#{err'}|]
|
||||||
@ -938,7 +939,7 @@ defaultLinks = fmap catMaybes . mapM runMaybeT $ -- Define the menu items of the
|
|||||||
}
|
}
|
||||||
, do
|
, do
|
||||||
mCurrentRoute <- getCurrentRoute
|
mCurrentRoute <- getCurrentRoute
|
||||||
|
|
||||||
return MenuItem
|
return MenuItem
|
||||||
{ menuItemType = NavbarRight
|
{ menuItemType = NavbarRight
|
||||||
, menuItemLabel = MsgMenuHelp
|
, menuItemLabel = MsgMenuHelp
|
||||||
@ -1226,6 +1227,14 @@ pageActions (CSubmissionR tid ssh csh shn cid SubShowR) =
|
|||||||
, menuItemModal = False
|
, menuItemModal = False
|
||||||
, menuItemAccessCallback' = return True
|
, menuItemAccessCallback' = return True
|
||||||
}
|
}
|
||||||
|
, MenuItem
|
||||||
|
{ menuItemType = PageActionPrime
|
||||||
|
, menuItemLabel = MsgCorrectorAssignTitle
|
||||||
|
, menuItemIcon = Nothing
|
||||||
|
, menuItemRoute = SomeRoute $ CSubmissionR tid ssh csh shn cid SAssignR
|
||||||
|
, menuItemModal = True
|
||||||
|
, menuItemAccessCallback' = return True
|
||||||
|
}
|
||||||
]
|
]
|
||||||
pageActions (CSheetR tid ssh csh shn SCorrR) =
|
pageActions (CSheetR tid ssh csh shn SCorrR) =
|
||||||
[ MenuItem
|
[ MenuItem
|
||||||
@ -1455,7 +1464,7 @@ routeNormalizers =
|
|||||||
hasChanged shn sheetName
|
hasChanged shn sheetName
|
||||||
return $ CSheetR tid ssh csh sheetName subRoute
|
return $ CSheetR tid ssh csh sheetName subRoute
|
||||||
|
|
||||||
|
|
||||||
-- How to run database actions.
|
-- How to run database actions.
|
||||||
instance YesodPersist UniWorX where
|
instance YesodPersist UniWorX where
|
||||||
type YesodPersistBackend UniWorX = SqlBackend
|
type YesodPersistBackend UniWorX = SqlBackend
|
||||||
@ -1525,7 +1534,7 @@ instance YesodAuth UniWorX where
|
|||||||
userEmail' = lookup (Attr "mail") ldapData
|
userEmail' = lookup (Attr "mail") ldapData
|
||||||
userDisplayName' = lookup (Attr "displayName") ldapData
|
userDisplayName' = lookup (Attr "displayName") ldapData
|
||||||
userSurname' = lookup (Attr "sn") ldapData
|
userSurname' = lookup (Attr "sn") ldapData
|
||||||
|
|
||||||
userAuthentication
|
userAuthentication
|
||||||
| isPWHash = error "PWHash should only work for users that are already known"
|
| isPWHash = error "PWHash should only work for users that are already known"
|
||||||
| otherwise = AuthLDAP
|
| otherwise = AuthLDAP
|
||||||
@ -1631,13 +1640,13 @@ instance YesodMail UniWorX where
|
|||||||
mailSmtp act = do
|
mailSmtp act = do
|
||||||
pool <- maybe (throwM MailNotAvailable) return =<< getsYesod appSmtpPool
|
pool <- maybe (throwM MailNotAvailable) return =<< getsYesod appSmtpPool
|
||||||
withResource pool act
|
withResource pool act
|
||||||
mailT ctx mail = defMailT ctx $ do
|
mailT ctx mail = defMailT ctx $ do
|
||||||
void setMailObjectId
|
void setMailObjectId
|
||||||
setDateCurrent
|
setDateCurrent
|
||||||
replaceMailHeader "Auto-Submitted" $ Just "auto-generated"
|
replaceMailHeader "Auto-Submitted" $ Just "auto-generated"
|
||||||
|
|
||||||
ret <- mail
|
ret <- mail
|
||||||
|
|
||||||
setMailSmtpData
|
setMailSmtpData
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
|
|||||||
@ -83,11 +83,7 @@ colTerm = sortable (Just "term") (i18nCell MsgTerm)
|
|||||||
|
|
||||||
colCourse :: IsDBTable m a => Colonnade _ CorrectionTableData (DBCell m a)
|
colCourse :: IsDBTable m a => Colonnade _ CorrectionTableData (DBCell m a)
|
||||||
colCourse = sortable (Just "course") (i18nCell MsgCourse)
|
colCourse = sortable (Just "course") (i18nCell MsgCourse)
|
||||||
$ \DBRow{ dbrOutput=(_, _, course, _, _) } ->
|
$ \DBRow{ dbrOutput=(_, _, (_,csh,tid,sid), _, _) } -> courseCellCL (tid,sid,csh)
|
||||||
let tid = course ^. _3
|
|
||||||
ssh = course ^. _4
|
|
||||||
csh = course ^. _2
|
|
||||||
in anchorCell (CourseR tid ssh csh CShowR) [whamlet|#{display csh}|]
|
|
||||||
|
|
||||||
colSheet :: IsDBTable m a => Colonnade _ CorrectionTableData (DBCell m a)
|
colSheet :: IsDBTable m a => Colonnade _ CorrectionTableData (DBCell m a)
|
||||||
colSheet = sortable (Just "sheet") (i18nCell MsgSheet)
|
colSheet = sortable (Just "sheet") (i18nCell MsgSheet)
|
||||||
@ -135,7 +131,7 @@ colSMatrikel :: IsDBTable m a => Colonnade _ CorrectionTableData (DBCell m a)
|
|||||||
colSMatrikel = sortable Nothing (i18nCell MsgMatrikelNr) $ \DBRow{ dbrOutput=(_, _, _, _, users) } -> let
|
colSMatrikel = sortable Nothing (i18nCell MsgMatrikelNr) $ \DBRow{ dbrOutput=(_, _, _, _, users) } -> let
|
||||||
protoCell = listCell (Map.toList users) $ \(userId, (User{..}, _)) -> anchorCellM (AdminUserR <$> encrypt userId) (maybe mempty toWidget userMatrikelnummer)
|
protoCell = listCell (Map.toList users) $ \(userId, (User{..}, _)) -> anchorCellM (AdminUserR <$> encrypt userId) (maybe mempty toWidget userMatrikelnummer)
|
||||||
in protoCell & cellAttrs <>~ [("class", "list--inline list--comma-separated")]
|
in protoCell & cellAttrs <>~ [("class", "list--inline list--comma-separated")]
|
||||||
|
|
||||||
colRating :: IsDBTable m a => Colonnade _ CorrectionTableData (DBCell m a)
|
colRating :: IsDBTable m a => Colonnade _ CorrectionTableData (DBCell m a)
|
||||||
colRating = sortable (Just "rating") (i18nCell MsgRating) $ \DBRow{ dbrOutput=(Entity subId Submission{..}, Entity _ Sheet{..}, course, _, _) } ->
|
colRating = sortable (Just "rating") (i18nCell MsgRating) $ \DBRow{ dbrOutput=(Entity subId Submission{..}, Entity _ Sheet{..}, course, _, _) } ->
|
||||||
let csh = course ^. _2
|
let csh = course ^. _2
|
||||||
@ -181,7 +177,7 @@ colCommentField = sortable Nothing (i18nCell MsgRatingComment) $ formCell
|
|||||||
|
|
||||||
|
|
||||||
type CorrectionTableExpr = (E.SqlExpr (Entity Course) `E.InnerJoin` E.SqlExpr (Entity Sheet) `E.InnerJoin` E.SqlExpr (Entity Submission)) `E.LeftOuterJoin` E.SqlExpr (Maybe (Entity User))
|
type CorrectionTableExpr = (E.SqlExpr (Entity Course) `E.InnerJoin` E.SqlExpr (Entity Sheet) `E.InnerJoin` E.SqlExpr (Entity Submission)) `E.LeftOuterJoin` E.SqlExpr (Maybe (Entity User))
|
||||||
|
|
||||||
makeCorrectionsTable :: ( IsDBTable m x, ToSortable h, Functor h )
|
makeCorrectionsTable :: ( IsDBTable m x, ToSortable h, Functor h )
|
||||||
=> _ -> Colonnade h CorrectionTableData (DBCell m x) -> PSValidator m x -> _ -> Handler (DBResult m x)
|
=> _ -> Colonnade h CorrectionTableData (DBCell m x) -> PSValidator m x -> _ -> Handler (DBResult m x)
|
||||||
makeCorrectionsTable whereClause dbtColonnade psValidator dbtProj' = do
|
makeCorrectionsTable whereClause dbtColonnade psValidator dbtProj' = do
|
||||||
@ -303,9 +299,10 @@ correctionsR whereClause (formColonnade -> displayColumns) psValidator actions =
|
|||||||
alreadyAssigned <- selectList [SubmissionId <-. subs, SubmissionRatingBy !=. Nothing] []
|
alreadyAssigned <- selectList [SubmissionId <-. subs, SubmissionRatingBy !=. Nothing] []
|
||||||
unless (null alreadyAssigned) $ do
|
unless (null alreadyAssigned) $ do
|
||||||
mr <- (toHtml . ) <$> getMessageRender
|
mr <- (toHtml . ) <$> getMessageRender
|
||||||
alreadyAssigned' <- forM alreadyAssigned $ \Entity{..} -> (, entityVal) <$> (encrypt entityKey :: DB CryptoFileNameSubmission)
|
alreadyAssigned' <- forM alreadyAssigned $ \Entity{..} -> (, entityVal) <$> (encrypt entityKey :: DB CryptoFileNameSubmission)
|
||||||
addMessage Warning =<< withUrlRenderer ($(ihamletFile "templates/messages/submissionsAlreadyAssigned.hamlet") mr)
|
addMessage Warning =<< withUrlRenderer ($(ihamletFile "templates/messages/submissionsAlreadyAssigned.hamlet") mr)
|
||||||
let unassigned = Set.fromList subs `Set.difference` Set.fromList (entityKey <$> alreadyAssigned)
|
let unassigned = Set.fromList subs `Set.difference` Set.fromList (entityKey <$> alreadyAssigned)
|
||||||
|
|
||||||
unless (null unassigned) $ do
|
unless (null unassigned) $ do
|
||||||
num <- updateWhereCount [SubmissionId <-. Set.toList unassigned]
|
num <- updateWhereCount [SubmissionId <-. Set.toList unassigned]
|
||||||
[ SubmissionRatingBy =. Just uid
|
[ SubmissionRatingBy =. Just uid
|
||||||
@ -337,7 +334,7 @@ correctionsR whereClause (formColonnade -> displayColumns) psValidator actions =
|
|||||||
alreadyAssigned <- selectList [SubmissionId <-. subs, SubmissionRatingBy !=. Nothing] []
|
alreadyAssigned <- selectList [SubmissionId <-. subs, SubmissionRatingBy !=. Nothing] []
|
||||||
unless (null alreadyAssigned) $ do
|
unless (null alreadyAssigned) $ do
|
||||||
mr <- (toHtml . ) <$> getMessageRender
|
mr <- (toHtml . ) <$> getMessageRender
|
||||||
alreadyAssigned' <- forM alreadyAssigned $ \Entity{..} -> (, entityVal) <$> (encrypt entityKey :: DB CryptoFileNameSubmission)
|
alreadyAssigned' <- forM alreadyAssigned $ \Entity{..} -> (, entityVal) <$> (encrypt entityKey :: DB CryptoFileNameSubmission)
|
||||||
addMessage Warning =<< withUrlRenderer ($(ihamletFile "templates/messages/submissionsAlreadyAssigned.hamlet") mr)
|
addMessage Warning =<< withUrlRenderer ($(ihamletFile "templates/messages/submissionsAlreadyAssigned.hamlet") mr)
|
||||||
let unassigned = Set.fromList subs `Set.difference` Set.fromList (entityKey <$> alreadyAssigned)
|
let unassigned = Set.fromList subs `Set.difference` Set.fromList (entityKey <$> alreadyAssigned)
|
||||||
unless (null unassigned) $ do
|
unless (null unassigned) $ do
|
||||||
@ -356,7 +353,7 @@ correctionsR whereClause (formColonnade -> displayColumns) psValidator actions =
|
|||||||
|
|
||||||
|
|
||||||
type ActionCorrections' = (ActionCorrections, AForm (HandlerT UniWorX IO) ActionCorrectionsData)
|
type ActionCorrections' = (ActionCorrections, AForm (HandlerT UniWorX IO) ActionCorrectionsData)
|
||||||
|
|
||||||
downloadAction :: ActionCorrections'
|
downloadAction :: ActionCorrections'
|
||||||
downloadAction = ( CorrDownload
|
downloadAction = ( CorrDownload
|
||||||
, pure CorrDownloadData
|
, pure CorrDownloadData
|
||||||
@ -483,8 +480,8 @@ postCorrectionR tid ssh csh shn cid = 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 -> pure Nothing
|
NotGraded -> pure Nothing
|
||||||
_otherwise -> aopt (pointsFieldMax $ preview (_grading . _maxPoints) sheetType)
|
_otherwise -> aopt (pointsFieldMax $ preview (_grading . _maxPoints) sheetType)
|
||||||
(fslpI MsgRatingPoints "Punktezahl")
|
(fslpI MsgRatingPoints "Punktezahl")
|
||||||
(Just submissionRatingPoints)
|
(Just submissionRatingPoints)
|
||||||
|
|
||||||
((corrResult, corrForm), corrEncoding) <- runFormPost . identForm FIDcorrection . renderAForm FormStandard $ (,,)
|
((corrResult, corrForm), corrEncoding) <- runFormPost . identForm FIDcorrection . renderAForm FormStandard $ (,,)
|
||||||
@ -500,7 +497,7 @@ postCorrectionR tid ssh csh shn cid = do
|
|||||||
case corrResult of
|
case corrResult of
|
||||||
FormMissing -> return ()
|
FormMissing -> return ()
|
||||||
FormFailure errs -> mapM_ (addMessage Error . toHtml) errs
|
FormFailure errs -> mapM_ (addMessage Error . toHtml) errs
|
||||||
FormSuccess (rated, ratingPoints', ratingComment')
|
FormSuccess (rated, ratingPoints', ratingComment')
|
||||||
| errs <- validateRating sheetType Rating'
|
| errs <- validateRating sheetType Rating'
|
||||||
{ ratingPoints=ratingPoints'
|
{ ratingPoints=ratingPoints'
|
||||||
, ratingComment=ratingComment'
|
, ratingComment=ratingComment'
|
||||||
@ -511,7 +508,7 @@ postCorrectionR tid ssh csh shn cid = do
|
|||||||
runDBJobs $ do
|
runDBJobs $ do
|
||||||
uid <- liftHandlerT requireAuthId
|
uid <- liftHandlerT requireAuthId
|
||||||
now <- liftIO getCurrentTime
|
now <- liftIO getCurrentTime
|
||||||
|
|
||||||
update sub [ SubmissionRatingBy =. Just uid
|
update sub [ SubmissionRatingBy =. Just uid
|
||||||
, SubmissionRatingTime =. (now <$ guard rated)
|
, SubmissionRatingTime =. (now <$ guard rated)
|
||||||
, SubmissionRatingPoints =. ratingPoints'
|
, SubmissionRatingPoints =. ratingPoints'
|
||||||
@ -522,7 +519,7 @@ postCorrectionR tid ssh csh shn cid = do
|
|||||||
|
|
||||||
when (rated && isNothing submissionRatingTime) $ do
|
when (rated && isNothing submissionRatingTime) $ do
|
||||||
$logDebugS "CorrectionR" [st|Rated #{tshow sub}|]
|
$logDebugS "CorrectionR" [st|Rated #{tshow sub}|]
|
||||||
queueDBJob . JobQueueNotification $ NotificationSubmissionRated sub
|
queueDBJob . JobQueueNotification $ NotificationSubmissionRated sub
|
||||||
|
|
||||||
redirect $ CSubmissionR tid ssh csh shn cid CorrectionR
|
redirect $ CSubmissionR tid ssh csh shn cid CorrectionR
|
||||||
|
|
||||||
@ -531,7 +528,7 @@ postCorrectionR tid ssh csh shn cid = do
|
|||||||
FormFailure errs -> mapM_ (addMessage Error . toHtml) errs
|
FormFailure errs -> mapM_ (addMessage Error . toHtml) errs
|
||||||
FormSuccess fileUploads -> do
|
FormSuccess fileUploads -> do
|
||||||
uid <- requireAuthId
|
uid <- requireAuthId
|
||||||
|
|
||||||
void . runDBJobs . runConduit $ transPipe (lift . lift) fileUploads .| extractRatingsMsg .| sinkSubmission uid (Right sub) True
|
void . runDBJobs . runConduit $ transPipe (lift . lift) fileUploads .| extractRatingsMsg .| sinkSubmission uid (Right sub) True
|
||||||
|
|
||||||
addMessageI Success MsgRatingFilesUpdated
|
addMessageI Success MsgRatingFilesUpdated
|
||||||
@ -545,7 +542,7 @@ postCorrectionR tid ssh csh shn cid = do
|
|||||||
_ -> notFound
|
_ -> notFound
|
||||||
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
|
||||||
@ -557,7 +554,7 @@ getCorrectionUserR tid ssh csh shn cid = do
|
|||||||
$(widgetFile "correction-user")
|
$(widgetFile "correction-user")
|
||||||
_ -> notFound
|
_ -> notFound
|
||||||
|
|
||||||
|
|
||||||
getCorrectionsUploadR, postCorrectionsUploadR :: Handler Html
|
getCorrectionsUploadR, postCorrectionsUploadR :: Handler Html
|
||||||
getCorrectionsUploadR = postCorrectionsUploadR
|
getCorrectionsUploadR = postCorrectionsUploadR
|
||||||
postCorrectionsUploadR = do
|
postCorrectionsUploadR = do
|
||||||
@ -577,7 +574,7 @@ postCorrectionsUploadR = do
|
|||||||
subs' <- traverse encrypt $ Set.toList subs :: Handler [CryptoFileNameSubmission]
|
subs' <- traverse encrypt $ Set.toList subs :: Handler [CryptoFileNameSubmission]
|
||||||
mr <- (toHtml .) <$> getMessageRender
|
mr <- (toHtml .) <$> getMessageRender
|
||||||
addMessage Success =<< withUrlRenderer ($(ihamletFile "templates/messages/correctionsUploaded.hamlet") mr)
|
addMessage Success =<< withUrlRenderer ($(ihamletFile "templates/messages/correctionsUploaded.hamlet") mr)
|
||||||
|
|
||||||
|
|
||||||
defaultLayout $
|
defaultLayout $
|
||||||
$(widgetFile "corrections-upload")
|
$(widgetFile "corrections-upload")
|
||||||
@ -692,17 +689,17 @@ postCorrectionsCreateR = do
|
|||||||
insertMany_ . flip map spGroup $ \SheetPseudonym{sheetPseudonymUser} -> SubmissionUser
|
insertMany_ . flip map spGroup $ \SheetPseudonym{sheetPseudonymUser} -> SubmissionUser
|
||||||
{ submissionUserUser = sheetPseudonymUser
|
{ submissionUserUser = sheetPseudonymUser
|
||||||
, submissionUserSubmission = subId
|
, submissionUserSubmission = subId
|
||||||
}
|
}
|
||||||
addMessageI Warning $ MsgSheetNoGroupSubmission sheetGroupDesc
|
addMessageI Warning $ MsgSheetNoGroupSubmission sheetGroupDesc
|
||||||
redirect CorrectionsGradeR
|
redirect CorrectionsGradeR
|
||||||
|
|
||||||
|
|
||||||
defaultLayout $
|
defaultLayout $
|
||||||
$(widgetFile "corrections-create")
|
$(widgetFile "corrections-create")
|
||||||
where
|
where
|
||||||
partitionEithers' :: [[Either a b]] -> ([[b]], [a])
|
partitionEithers' :: [[Either a b]] -> ([[b]], [a])
|
||||||
partitionEithers' = runWriter . mapM (WriterT . Identity . swap . partitionEithers)
|
partitionEithers' = runWriter . mapM (WriterT . Identity . swap . partitionEithers)
|
||||||
|
|
||||||
textToList :: Textarea -> Handler (Either UniWorXMessage [[Pseudonym]])
|
textToList :: Textarea -> Handler (Either UniWorXMessage [[Pseudonym]])
|
||||||
textToList (map (map Text.strip . Text.splitOn ",") . filter (not . Text.null) . Text.lines . unTextarea -> ws)
|
textToList (map (map Text.strip . Text.splitOn ",") . filter (not . Text.null) . Text.lines . unTextarea -> ws)
|
||||||
= let
|
= let
|
||||||
@ -735,7 +732,7 @@ postCorrectionsGradeR = do
|
|||||||
psValidator = def
|
psValidator = def
|
||||||
& defaultSorting [("ratingtime", SortDesc)] :: PSValidator (RWST (Maybe (Env, FileEnv), UniWorX, [Lang]) Enctype Ints (HandlerT UniWorX IO)) (FormResult (DBFormResult CorrectionTableData SubmissionId (Bool, Maybe Points, Maybe Text)))
|
& defaultSorting [("ratingtime", SortDesc)] :: PSValidator (RWST (Maybe (Env, FileEnv), UniWorX, [Lang]) Enctype Ints (HandlerT UniWorX IO)) (FormResult (DBFormResult CorrectionTableData SubmissionId (Bool, Maybe Points, Maybe Text)))
|
||||||
unFormResult = getDBFormResult $ \DBRow{ dbrOutput = (Entity _ sub@Submission{..}, _, _, _, _) } -> (submissionRatingDone sub, submissionRatingPoints, submissionRatingComment)
|
unFormResult = getDBFormResult $ \DBRow{ dbrOutput = (Entity _ sub@Submission{..}, _, _, _, _) } -> (submissionRatingDone sub, submissionRatingPoints, submissionRatingComment)
|
||||||
|
|
||||||
tableForm <- makeCorrectionsTable whereClause displayColumns psValidator $ \i@(Entity subId _, Entity _ Sheet{ sheetName = shn }, (_, csh, tid, ssh), _, _) -> do
|
tableForm <- makeCorrectionsTable whereClause displayColumns psValidator $ \i@(Entity subId _, Entity _ Sheet{ sheetName = shn }, (_, csh, tid, ssh), _, _) -> do
|
||||||
cID <- encrypt subId
|
cID <- encrypt subId
|
||||||
void . assertM (== Authorized) . lift $ evalAccessDB (CSubmissionR tid ssh csh shn cID CorrectionR) True
|
void . assertM (== Authorized) . lift $ evalAccessDB (CSubmissionR tid ssh csh shn cID CorrectionR) True
|
||||||
@ -762,3 +759,43 @@ postCorrectionsGradeR = do
|
|||||||
|
|
||||||
defaultLayout $
|
defaultLayout $
|
||||||
$(widgetFile "corrections-grade")
|
$(widgetFile "corrections-grade")
|
||||||
|
|
||||||
|
|
||||||
|
getSAssignR, postSAssignR :: TermId -> SchoolId -> CourseShorthand -> SheetName -> CryptoFileNameSubmission -> Handler Html
|
||||||
|
getSAssignR = postSAssignR
|
||||||
|
postSAssignR tid ssh csh shn cID = do
|
||||||
|
let actionUrl = CSubmissionR tid ssh csh shn cID SAssignR
|
||||||
|
sId <- decrypt cID
|
||||||
|
(currentCorrector, sheetCorrectors) <- runDB $ do
|
||||||
|
Submission{submissionRatingBy, submissionSheet} <- get404 sId
|
||||||
|
-- Beginn Verify that CryptoId matches ordinary prameters
|
||||||
|
-- Necessarry, since authorisation checks those parameters only, but can be changed by user!
|
||||||
|
Sheet{sheetCourse, sheetName} <- get404 submissionSheet
|
||||||
|
Course{courseTerm, courseSchool, courseShorthand} <- get404 sheetCourse
|
||||||
|
let cidMatches = and [tid==courseTerm, ssh==courseSchool, csh==courseShorthand, shn==sheetName]
|
||||||
|
unless cidMatches $ invalidArgsI [MsgErrorCryptoIdMismatch]
|
||||||
|
-- End Verification
|
||||||
|
sheetCorrectors <- map (sheetCorrectorUser . entityVal) <$> selectList [SheetCorrectorSheet ==. submissionSheet] []
|
||||||
|
userCorrector <- traverse getJustEntity submissionRatingBy
|
||||||
|
return (userCorrector, maybe id (:) submissionRatingBy sheetCorrectors)
|
||||||
|
|
||||||
|
$logDebugS "SAssignR" $ tshow currentCorrector
|
||||||
|
let correctorField = selectField $ optionsPersistCryptoId [UserId <-. sheetCorrectors] [Asc UserSurname, Asc UserDisplayName] userDisplayName
|
||||||
|
((corrResult, corrForm), corrEncoding) <- runFormPost . renderAForm FormStandard $
|
||||||
|
aopt correctorField (fslI MsgCorrector) (Just currentCorrector)
|
||||||
|
<* submitButton
|
||||||
|
formResult corrResult $ \(fmap entityKey -> mbUserId) -> do
|
||||||
|
when (mbUserId /= fmap entityKey currentCorrector) . runDB $ do
|
||||||
|
now <- liftIO getCurrentTime
|
||||||
|
update sId [ SubmissionRatingBy =. mbUserId
|
||||||
|
, SubmissionRatingAssigned =. (now <$ mbUserId)
|
||||||
|
]
|
||||||
|
addMessageI Success MsgCorrectorUpdated
|
||||||
|
redirect actionUrl
|
||||||
|
defaultLayout $ do
|
||||||
|
setTitleI MsgCorrectorAssignTitle
|
||||||
|
$(widgetFile "submission-assign")
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -1,2 +1,2 @@
|
|||||||
<form .form-horizontal method=post action=@{actionUrl}#forms enctype=#{formEnctype}>
|
<form method=post action=@{actionUrl}#forms enctype=#{formEnctype}>
|
||||||
^{formWidget}
|
^{formWidget}
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
$maybe text <- formText
|
$maybe text <- formText
|
||||||
<h3>
|
<h3>
|
||||||
_{text}
|
_{text}
|
||||||
<form .form-horizontal method=post action=@{actionUrl}#forms enctype=#{formEnctype}>
|
<form method=post action=@{actionUrl}#forms enctype=#{formEnctype}>
|
||||||
^{formWidget}
|
^{formWidget}
|
||||||
|
|||||||
2
templates/submission-assign.hamlet
Normal file
2
templates/submission-assign.hamlet
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
<form method=post action=@{actionUrl} enctype=#{corrEncoding}>
|
||||||
|
^{corrForm}
|
||||||
Reference in New Issue
Block a user