From 2fd060d55b7f027fa731dcb5b7d706e71d9ba413 Mon Sep 17 00:00:00 2001 From: Gregor Kleen Date: Thu, 16 Jul 2020 19:28:37 +0200 Subject: [PATCH] feat(course-comm): recipient categories for sheets and exams --- frontend/src/app.sass | 4 +++ messages/uniworx/de-de-formal.msg | 30 ++++++++++--------- messages/uniworx/en-eu.msg | 2 ++ src/Handler/Course/Communication.hs | 28 +++++++++++++++-- src/Handler/Utils/Communication.hs | 12 ++++++++ .../communication/recipientLayout.hamlet | 4 +++ 6 files changed, 63 insertions(+), 17 deletions(-) diff --git a/frontend/src/app.sass b/frontend/src/app.sass index fa4d2a2f1..885b7fa49 100644 --- a/frontend/src/app.sass +++ b/frontend/src/app.sass @@ -1163,6 +1163,10 @@ a.breadcrumbs__home font-weight: 600 opacity: 1 +.recipient-categories + overflow: auto + max-height: 75vh + .recipient-category max-width: 400px padding: 3px 0 diff --git a/messages/uniworx/de-de-formal.msg b/messages/uniworx/de-de-formal.msg index 8a185e148..cf8c9b568 100644 --- a/messages/uniworx/de-de-formal.msg +++ b/messages/uniworx/de-de-formal.msg @@ -449,7 +449,7 @@ UnauthorizedCorrectorAny: Sie sind nicht als Korrektor für eine Veranstaltung e UnauthorizedRegistered: Sie sind nicht als Teilnehmer für diese Veranstaltung registriert. UnauthorizedAllocationRegistered: Sie sind nicht als Teilnehmer für diese Zentralanmeldung registriert. UnauthorizedExamResult: Sie haben keine Ergebnisse in dieser Prüfung. -UnauthorizedExamOccurrenceRegistration: Anmeldung zur Klausur erfolgt nicht inkl. Raum/Termin. +UnauthorizedExamOccurrenceRegistration: Anmeldung zur Prüfung erfolgt nicht inkl. Raum/Termin. UnauthorizedExternalExamResult: Sie haben keine Ergebnisse in dieser Prüfung. UnauthorizedParticipant: Angegebener Benutzer ist nicht als Teilnehmer dieser Veranstaltung registriert. UnauthorizedParticipantSelf: Sie sind kein Teilnehmer dieser Veranstaltung. @@ -661,7 +661,7 @@ SubmissionUsers: Studenten Rating: Korrektur RatingPoints: Punkte RatingDone: Bewertung abgeschlossen -RatingDoneTip: Das Korrekturergebnis ist nur dann für die Abgebenden sichtbar und kann gegen etwaige Klausur-Bonuspunkte verrechnet werden, wenn die Bewertung abgeschlossen ist. +RatingDoneTip: Das Korrekturergebnis ist nur dann für die Abgebenden sichtbar und kann gegen etwaige Prüfungs-Bonuspunkte verrechnet werden, wenn die Bewertung abgeschlossen ist. RatingPercent: Erreicht RatingFiles: Korrigierte Dateien RatingFilesTip: Hier hochgeladene Dateien ersetzen ggf. die bestehende korrigierte Version der Abgabe vollständig (nicht erneut hochgeladene Dateien werden gelöscht). Die original abgegebene Version bleibt erhalten. @@ -749,7 +749,7 @@ TimeFormat: Uhrzeitformat DownloadFiles: Dateien automatisch herunterladen DownloadFilesTip: Wenn gesetzt werden Dateien automatisch als Download behandelt, ansonsten ist das Verhalten browserabhängig (es können z.B. PDFs im Browser geöffnet werden). WarningDays: Fristen-Vorschau -WarningDaysTip: Wie viele Tage im Voraus sollen Fristen von Klausuren etc. auf Ihrer Startseite angezeigt werden? +WarningDaysTip: Wie viele Tage im Voraus sollen Fristen von Prüfungen etc. auf Ihrer Startseite angezeigt werden? NotificationSettings: Erwünschte Benachrichtigungen UserSchools: Relevante Institute UserSchoolsTip: Sie erhalten nur institutweite Benachrichtigungen für Institute, die hier ausgewählt sind. @@ -1039,7 +1039,7 @@ SheetTypeBonus grading@SheetGrading: Bonus SheetTypeNormal grading@SheetGrading: Normal SheetTypeInformational grading@SheetGrading: Ohne Anrechnung SheetTypeNotGraded: Keine Korrektur -SheetTypeInfoNormalLecturer: Normale Blätter werden zur Berechnung eines etwaigen Klausurbonus herangezogen. Der Bonus kann sowohl anhand der zu bestehenden Blätter als auch der erreichbaren Maximalpunktzahl automatisch oder manuell berechnet werden. +SheetTypeInfoNormalLecturer: Normale Blätter werden zur Berechnung eines etwaigen Prüfungsbonus herangezogen. Der Bonus kann sowohl anhand der zu bestehenden Blätter als auch der erreichbaren Maximalpunktzahl automatisch oder manuell berechnet werden. SheetTypeInfoNotGraded: Keine Korrektur bedeutet, dass es gar kein Feedback gibt. SheetTypeInfoBonus: Bonus Blätter zählen normal, erhöhen aber nicht die maximal erreichbare Punktzahl bzw. Anzahl zu bestehender Blätter. SheetTypeInfoInformational: Blätter ohne Anrechnung werden nirgends angerechnet, die Bewertung durch den Korrektor dient lediglich zur Information der Teilnehmer. @@ -1418,7 +1418,7 @@ AuthTagDeprecated: Seite ist nicht überholt AuthTagDevelopment: Seite ist nicht in Entwicklung AuthTagLecturer: Nutzer ist Dozent AuthTagCorrector: Nutzer ist Korrektor -AuthTagExamCorrector: Nutzer ist Klausurkorrektor +AuthTagExamCorrector: Nutzer ist Prüfungskorrektor AuthTagTutor: Nutzer ist Tutor AuthTagTutorControl: Tutoren haben Kontrolle über ihre Tutorium AuthTagTime: Zeitliche Einschränkungen sind erfüllt @@ -1430,7 +1430,7 @@ AuthTagTutorialRegistered: Nutzer ist Tutoriumsteilnehmer AuthTagExamRegistered: Nutzer ist Prüfungsteilnehmer AuthTagExamResult: Nutzer hat Prüfungsergebnisse AuthTagExamOccurrenceRegistered: Nutzer ist für Prüfungsraum/-termin angemeldet -AuthTagExamOccurrenceRegistration: Anmeldung zur Klausur erfolgt inkl. Raum/Termin +AuthTagExamOccurrenceRegistration: Anmeldung zur Prüfung erfolgt inkl. Raum/Termin AuthTagParticipant: Nutzer ist mit Kurs assoziiert AuthTagApplicant: Nutzer ist mit Bewerber zum Kurs AuthTagRegisterGroup: Nutzer ist nicht Mitglied eines anderen Tutoriums mit der selben Registrierungs-Gruppe @@ -1486,6 +1486,8 @@ RGCourseCorrectors: Korrektoren RGCourseTutors: Tutoren RGTutorialParticipants tutn@TutorialName: Tutorium-Teilnehmer (#{tutn}) RGCourseUnacceptedApplicants: Nicht akzeptierte Bewerber +RGExamRegistered examn@ExamName: Angemeldet zur Prüfung „#{examn}“ +RGSheetSubmittor shn@SheetName: Abgebende für das Übungsblatt „#{shn}“ MultiSelectFieldTip: Mehrfach-Auswahl ist möglich (Umschalt bzw. Strg) MultiEmailFieldTip: Es sind mehrere, Komma-separierte, E-Mail-Adressen möglich @@ -1723,7 +1725,7 @@ ExamNoBonus': Kein automatischer Bonus ExamBonusPoints': Umrechnung von Übungspunkten ExamBonusManual': Manuelle Berechnung -ExamRegisterForOccurrence: Anmeldung zur Klausur erfolgt durch Anmeldung zu einem Termin/Raum +ExamRegisterForOccurrence: Anmeldung zur Prüfung erfolgt durch Anmeldung zu einem Termin/Raum ExamBonusAchieved: Bonuspunkte @@ -2259,13 +2261,13 @@ MailTitleChangeUserDisplayEmail displayName@Text: #{displayName} möchte diese E ExamOfficeOptOutsChanged: Zuständige Prüfungsbeauftragte erfolgreich angepasst -ExamCloseHeading: Klausur abschließen -BtnCloseExam: Klausur abschließen -ExamCloseTip: Wenn eine Klausur abgeschlossen wird, werden Prüfungsbeauftragte, die im System Noten einsehen, benachrichtigt und danach bei Änderungen informiert. -ExamCloseReminder: Bitte schließen Sie die Klausur frühstmöglich, sobald die Prüfungsleistungen sich voraussichtlich nicht mehr ändern werden. Z.B. direkt nach der Klausureinsicht. -ExamDidClose: Klausur erfolgreich abgeschlossen +ExamCloseHeading: Prüfung abschließen +BtnCloseExam: Prüfung abschließen +ExamCloseTip: Wenn eine Prüfung abgeschlossen wird, werden Prüfungsbeauftragte, die im System Noten einsehen, benachrichtigt und danach bei Änderungen informiert. +ExamCloseReminder: Bitte schließen Sie die Prüfung frühstmöglich, sobald die Prüfungsleistungen sich voraussichtlich nicht mehr ändern werden. Z.B. direkt nach der Klausureinsicht. +ExamDidClose: Prüfung erfolgreich abgeschlossen -ExamClosedSince time@Text: Klausur abgeschlossen seit #{time} +ExamClosedSince time@Text: Prüfung abgeschlossen seit #{time} LecturerInfoTooltipNew: Neues Feature LecturerInfoTooltipProblem: Feature mit bekannten Problemen @@ -2640,7 +2642,7 @@ RatingYAMLMetaComment: Meta-Informationen zur Korrektur (werden beim Hochladen i RatingYAMLRatingComment: Bewertung RatingYAMLChangePointsComment: TODO: Hier die Punktezahl statt null eintragen (bis zu zwei Nachkommastellen, Punkt als Dezimalseparator; z.B. 17.03) RatingYAMLChangePassedComment: TODO: Hier true oder false statt null eintragen (true entspricht Bestanden) -RatingYAMLChangeDoneComment: TODO: Von false auf true setzen, sobald Bewertung abgeschlossen; sonst Korrektur für die Studierenden nicht sichtbar und keine Anrechnung auf Klausurbonus +RatingYAMLChangeDoneComment: TODO: Von false auf true setzen, sobald Bewertung abgeschlossen; sonst Korrektur für die Studierenden nicht sichtbar und keine Anrechnung auf Prüfungsbonus RatingYAMLChangeCommentComment: TODO: Korrektur-Kommentar für die Studierenden unterhalb der Abtrennung (...) eintragen RatingYAMLSubmissionIdComment: Abgabenummer; wird beim Hochladen mit dem Dateinamen abgeglichen diff --git a/messages/uniworx/en-eu.msg b/messages/uniworx/en-eu.msg index 36dff2046..c782ed753 100644 --- a/messages/uniworx/en-eu.msg +++ b/messages/uniworx/en-eu.msg @@ -1486,6 +1486,8 @@ RGCourseCorrectors: Course correctors RGCourseTutors: Course tutors RGTutorialParticipants tutn: Tutorial participants (#{tutn}) RGCourseUnacceptedApplicants: Applicants not accepted +RGExamRegistered examn: Registered for exam “#{examn}” +RGSheetSubmittor shn: Submitted for exercise sheet “#{shn}” MultiSelectFieldTip: Multiple selections are possible (Shift or Ctrl) MultiEmailFieldTip: Multiple emails addresses may be specified (comma-separated) diff --git a/src/Handler/Course/Communication.hs b/src/Handler/Course/Communication.hs index 0833d1f35..dd833eccd 100644 --- a/src/Handler/Course/Communication.hs +++ b/src/Handler/Course/Communication.hs @@ -15,7 +15,7 @@ import qualified Database.Esqueleto as E getCCommR, postCCommR :: TermId -> SchoolId -> CourseShorthand -> Handler Html getCCommR = postCCommR postCCommR tid ssh csh = do - (cid, tuts) <- runDB $ do + (cid, tuts, exams, sheets) <- runDB $ do cid <- getKeyBy404 $ TermSchoolCourseShort tid ssh csh tuts' <- selectKeysList [TutorialCourse ==. cid] [] tuts <- forM tuts' $ \tutid -> do @@ -26,7 +26,29 @@ postCCommR tid ssh csh = do E.where_ $ participant E.^. TutorialParticipantTutorial E.==. E.val tutid return user ) - return (cid, tuts) + + exams' <- selectKeysList [ExamCourse ==. cid] [] + exams <- forM exams' $ \examid -> do + cID <- encrypt examid + return ( RGExamRegistered cID + , E.from $ \(user `E.InnerJoin` examRegistration) -> do + E.on $ user E.^. UserId E.==. examRegistration E.^. ExamRegistrationUser + E.where_ $ examRegistration E.^. ExamRegistrationExam E.==. E.val examid + return user + ) + + sheets' <- selectKeysList [SheetCourse ==. cid] [] + sheets <- forM sheets' $ \sheetid -> do + cID <- encrypt sheetid + return ( RGSheetSubmittor cID + , E.from $ \(user `E.InnerJoin` submissionUser `E.InnerJoin` submission) -> E.distinctOnOrderBy [E.asc $ user E.^. UserIdent] $ do + E.on $ submission E.^. SubmissionId E.==. submissionUser E.^. SubmissionUserSubmission + E.on $ user E.^. UserId E.==. submissionUser E.^. SubmissionUserUser + E.where_ $ submission E.^. SubmissionSheet E.==. E.val sheetid + return user + ) + + return (cid, tuts, exams, sheets) commR CommunicationRoute { crHeading = SomeMessage . prependCourseTitle tid ssh csh $ SomeMessage MsgCommCourseHeading @@ -74,7 +96,7 @@ postCCommR tid ssh csh = do E.&&. courseParticipant E.^. CourseParticipantState E.==. E.val CourseParticipantActive return user ) - ] ++ tuts + ] ++ tuts ++ exams ++ sheets , crRecipientAuth = Just $ \uid -> do cID <- encrypt uid evalAccessDB (CourseR tid ssh csh $ CUserR cID) False diff --git a/src/Handler/Utils/Communication.hs b/src/Handler/Utils/Communication.hs index 66effed5c..0743d8902 100644 --- a/src/Handler/Utils/Communication.hs +++ b/src/Handler/Utils/Communication.hs @@ -24,6 +24,8 @@ import qualified Data.Conduit.Combinators as C data RecipientGroup = RGCourseParticipants | RGCourseLecturers | RGCourseCorrectors | RGCourseTutors | RGCourseUnacceptedApplicants | RGTutorialParticipants CryptoUUIDTutorial + | RGExamRegistered CryptoUUIDExam + | RGSheetSubmittor CryptoUUIDSheet deriving (Eq, Ord, Read, Show, Generic, Typeable) instance LowerBounded RecipientGroup where @@ -183,6 +185,16 @@ commR CommunicationRoute{..} = do tutId <- decrypt cID Tutorial{..} <- liftHandler . runDBRead $ get404 tutId i18n $ MsgRGTutorialParticipants tutorialName + rgExamRegisteredCaption :: CryptoUUIDExam -> Widget + rgExamRegisteredCaption cID = do + eId <- decrypt cID + Exam{..} <- liftHandler . runDBRead $ get404 eId + i18n $ MsgRGExamRegistered examName + rgSheetSubmittorCaption :: CryptoUUIDSheet -> Widget + rgSheetSubmittorCaption cID = do + sId <- decrypt cID + Sheet{..} <- liftHandler . runDBRead $ get404 sId + i18n $ MsgRGSheetSubmittor sheetName $(widgetFile "widgets/communication/recipientLayout") miDelete :: Map (BoundedPosition RecipientCategory, ListPosition) (Either UserEmail UserId) -> (BoundedPosition RecipientCategory, ListPosition) -> MaybeT (MForm Handler) (Map (BoundedPosition RecipientCategory, ListPosition) (BoundedPosition RecipientCategory, ListPosition)) -- miDelete liveliness@(MapLiveliness lMap) (BoundedPosition RecipientCustom, delPos) = mappend (Map.fromSet id . Set.filter (\(BoundedPosition c, _) -> c /= RecipientCustom) $ review liveCoords liveliness) . fmap (BoundedPosition RecipientCustom, ) . Map.mapKeysMonotonic (BoundedPosition RecipientCustom, ) <$> miDeleteList (lMap ! BoundedPosition RecipientCustom) delPos diff --git a/templates/widgets/communication/recipientLayout.hamlet b/templates/widgets/communication/recipientLayout.hamlet index 416cbc1d5..ad63a7eb7 100644 --- a/templates/widgets/communication/recipientLayout.hamlet +++ b/templates/widgets/communication/recipientLayout.hamlet @@ -20,6 +20,10 @@ $if not (null activeCategories) ^{rgTutorialParticipantsCaption tutid} $of RecipientGroup RGCourseUnacceptedApplicants _{MsgRGCourseUnacceptedApplicants} + $of RecipientGroup (RGExamRegistered eid) + ^{rgExamRegisteredCaption eid} + $of RecipientGroup (RGSheetSubmittor sid) + ^{rgSheetSubmittorCaption sid} $if hasContent category