feat(external-exams): create new exams
This commit is contained in:
parent
fa3521d6db
commit
94bb3911cb
@ -401,9 +401,9 @@ UnauthorizedToken404: Authorisierungs-Tokens können nicht auf Fehlerseiten ausg
|
||||
UnauthorizedSiteAdmin: Sie sind kein System-weiter Administrator.
|
||||
UnauthorizedSchoolAdmin: Sie sind nicht als Administrator für dieses Institut eingetragen.
|
||||
UnauthorizedAdminEscalation: Sie sind nicht Administrator für alle Institute, für die dieser Nutzer Administrator oder Veranstalter ist.
|
||||
UnauthorizedExamOffice: Sie sind nicht Teil eines Prüfungsamts.
|
||||
UnauthorizedExamExamOffice: Es existieren keine Prüfungsergebnisse für Nutzer, für die Sie Teil eines assoziierten Prüfungsamts sind.
|
||||
UnauthorizedExternalExamExamOffice: Es existieren keine Prüfungsergebnisse für Nutzer, für die Sie Teil eines assoziierten Prüfungsamts sind.
|
||||
UnauthorizedExamOffice: Sie sind nicht mit Prüfungsverwaltung beauftragt.
|
||||
UnauthorizedExamExamOffice: Es existieren keine Prüfungsergebnisse für Nutzer, für die Sie mit der Prüfungsverwaltung beauftragt sind.
|
||||
UnauthorizedExternalExamExamOffice: Es existieren keine Prüfungsergebnisse für Nutzer, für die Sie mit der Prüfungsverwaltung beauftragt sind.
|
||||
UnauthorizedSchoolLecturer: Sie sind nicht als Veranstalter für dieses Institut eingetragen.
|
||||
UnauthorizedLecturer: Sie sind nicht als Veranstalter für diese Veranstaltung eingetragen.
|
||||
UnauthorizedAllocationLecturer: Sie sind nicht als Veranstalter für eine Veranstaltung dieser Zentralanmeldung eingetragen.
|
||||
@ -1000,7 +1000,7 @@ NotificationTriggerKindCorrector: Für Korrektoren
|
||||
NotificationTriggerKindLecturer: Für Dozenten
|
||||
NotificationTriggerKindCourseLecturer: Für Kursverwalter
|
||||
NotificationTriggerKindAdmin: Für Administratoren
|
||||
NotificationTriggerKindExamOffice: Für das Prüfungsamt
|
||||
NotificationTriggerKindExamOffice: Für Prüfungsverwalter
|
||||
NotificationTriggerKindEvaluation: Für Vorlesungsumfragen
|
||||
NotificationTriggerKindAllocationStaff: Für Zentralanmeldungen (Dozenten)
|
||||
NotificationTriggerKindAllocationParticipant: Für Zentralanmeldungen
|
||||
@ -1127,7 +1127,7 @@ MenuCourseMembers: Kursteilnehmer
|
||||
MenuCourseAddMembers: Kursteilnehmer hinzufügen
|
||||
MenuCourseCommunication: Kursmitteilung (E-Mail)
|
||||
MenuCourseApplications: Bewerbungen
|
||||
MenuCourseExamOffice: Prüfungsämter
|
||||
MenuCourseExamOffice: Prüfungsbeauftragte
|
||||
MenuTermShow: Semester
|
||||
MenuSubmissionDelete: Abgabe löschen
|
||||
MenuUsers: Benutzer
|
||||
@ -1267,7 +1267,7 @@ AuthPredsActive: Aktive Authorisierungsprädikate
|
||||
AuthPredsActiveChanged: Authorisierungseinstellungen für aktuelle Sitzung gespeichert
|
||||
AuthTagFree: Seite ist universell zugänglich
|
||||
AuthTagAdmin: Nutzer ist Administrator
|
||||
AuthTagExamOffice: Nutzer ist Teil eines Prüfungsamts
|
||||
AuthTagExamOffice: Nutzer ist mit Prüfungsverwaltung beauftragt
|
||||
AuthTagToken: Nutzer präsentiert Authorisierungs-Token
|
||||
AuthTagNoEscalation: Nutzer-Rechte werden nicht auf fremde Institute ausgeweitet
|
||||
AuthTagDeprecated: Seite ist nicht überholt
|
||||
@ -1522,9 +1522,9 @@ ExamFinishedOffice: Noten bekannt gegeben
|
||||
ExamFinishedParticipant: Bewertung vorrausichtlich abgeschlossen
|
||||
ExamFinishedTip: Zeitpunkt zu dem Prüfungergebnisse den Teilnehmern gemeldet werden
|
||||
ExamClosed: Noten gemeldet
|
||||
ExamClosedTip: Prüfungsämter, die im System Noten einsehen, werden zu diesem Zeitpunkt benachrichtigt und danach bei Änderungen informiert
|
||||
ExamClosedTip: Prüfungsbeauftraget, die im System Noten einsehen, werden zu diesem Zeitpunkt benachrichtigt und danach bei Änderungen informiert
|
||||
ExamShowGrades: Klausur ist benotet
|
||||
ExamShowGradesTip: Sollen genaue Noten angezeigt werden, oder sollen Teilnehmer und Prüfungsämter nur informiert werden, ob die Klausur bestanden wurde?
|
||||
ExamShowGradesTip: Sollen genaue Noten angezeigt werden, oder sollen Teilnehmer und Prüfungsbeauftragte nur informiert werden, ob die Klausur bestanden wurde?
|
||||
ExamPublicStatistics: Statistik veröffentlichen
|
||||
ExamPublicStatisticsTip: Soll die automatisch berechnete statistische Auswertung auch den Teilnehmern angezeigt werden, sobald diese ihre Noten einsehen können?
|
||||
ExamAutomaticGrading: Automatische Notenberechnung
|
||||
@ -1938,7 +1938,7 @@ SchoolExists ssh@SchoolId: Institut „#{ssh}“ existiert bereits
|
||||
SchoolAdmin: Admin
|
||||
SchoolLecturer: Dozent
|
||||
SchoolEvaluation: Kursumfragenverwaltung
|
||||
SchoolExamOffice: Prüfungsamt
|
||||
SchoolExamOffice: Prüfungsverwaltung
|
||||
|
||||
ApplicationEditTip: Während des Bewerbungszeitraums können eigene Bewerbungen beliebig angepasst und auch wieder zurückgezogen werden.
|
||||
|
||||
@ -2016,10 +2016,10 @@ MailSubjectChangeUserDisplayEmail: Diese E-Mail Adresse in Uni2work veröffentli
|
||||
MailIntroChangeUserDisplayEmail displayEmail@UserEmail: Der oben genannte Benutzer möchte „#{displayEmail}“ als öffentliche Adresse, assoziiert mit sich selbst, angeben. Wenn Sie diese Aktion nicht selbst ausgelöst haben, ignorieren Sie diese Mitteilung bitte!
|
||||
MailTitleChangeUserDisplayEmail displayName@Text: #{displayName} möchte diese E-Mail Adresse in Uni2work veröffentlichen
|
||||
|
||||
ExamOfficeOptOutsChanged: Zuständige Prüfungsämter erfolgreich angepasst
|
||||
ExamOfficeOptOutsChanged: Zuständige Prüfungsbeauftragte erfolgreich angepasst
|
||||
|
||||
BtnCloseExam: Klausur abschließen
|
||||
ExamCloseTip: Wenn eine Klausur abgeschlossen wird, werden Prüfungsämter, die im System Noten einsehen, benachrichtigt und danach bei Änderungen informiert.
|
||||
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
|
||||
|
||||
@ -2220,3 +2220,26 @@ Deficit: Defizit
|
||||
MetricNoSamples: Keine Messwerte
|
||||
MetricName: Name
|
||||
MetricValue: Wert
|
||||
|
||||
ExternalExamSemester: Semester
|
||||
ExternalExamSchool: Institut
|
||||
ExternalExamCourseName: Veranstaltung
|
||||
ExternalExamCourseNameTip: Muss nur innerhalb von Semester und Institut eindeutig sein.
|
||||
ExternalExamCourseNamePlaceholder: Analysis I, Programmierung und Modellierung, ...
|
||||
ExternalExamExamName: Prüfung
|
||||
ExternalExamExamNameTip: Muss innerhalb der Veranstaltung eindeutig sein.
|
||||
ExternalExamExamNamePlaceholder: Klausur, Nachklausur, Projektabnahme, ...
|
||||
ExternalExamDefaultTime: Voreingestellter Zeitpunkt
|
||||
ExternalExamDefaultTimePlaceholder: Zeitpunkt
|
||||
ExternalExamDefaultTimeTip: Der Zeitpunkt zu dem die Prüfung abgelegt wurde, muss pro Teilnehmer festgelegt werden. Der hier angegebene Zeitpunkt wird als Standardwert für Teilnehmer verwendet, bei denen später nicht ein abweichender Zeitpunkt angegeben wird.
|
||||
ExternalExamShowGrades: Klausur ist benotet
|
||||
ExternalExamShowGradesTip: Sollen genaue Noten angezeigt werden, oder sollen Teilnehmer und Prüfungsbeauftragte nur informiert werden, ob die Klausur bestanden wurde?
|
||||
ExternalExamExamOfficeSchools: Zusätzliche Institute
|
||||
ExternalExamExamOfficeSchoolsTip: Prüfungsbeauftragte von Instituten, die Sie hier angeben, erhalten im System (zusätzlich zum angegebenen primären Institut) volle Einsicht in sämtliche für diese Prüfung hinterlegten Leistungen, unabhängig von den Studiendaten der Teilnehmer.
|
||||
ExternalExamStaff: Assoziierte Personen
|
||||
ExternalExamStaffTip: Assoziierte Personen werden den Prüfungsbeauftragten und Teilnehmern angezeigt und dürfen Leistungen für die Prüfung hinterlegen.
|
||||
ExternalExamStaffAlreadyAdded: Person wurde bereits der Prüfung hinzugefügt
|
||||
ExternalExamUserMustBeStaff: Sie selbst müssen stets assoziierte Person sein, für die externen Prüfungen, die Sie anlegen
|
||||
ExternalExamCourseExists: Der angegebene Kurs existiert im System. Prüfungen sollten daher direkt beim Kurs (statt extern) hinterlegt werden.
|
||||
ExternalExamExists coursen@CourseName examn@ExamName: Prüfung „#{examn}“ für Kurs „#{coursen}“ existiert bereits.
|
||||
ExternalExamCreated coursen@CourseName examn@ExamName: Prüfung „#{examn}“ für Kurs „#{coursen}“ erfolgreich angelegt.
|
||||
@ -401,6 +401,7 @@ UnauthorizedSchoolAdmin: You are no administrator for this department.
|
||||
UnauthorizedAdminEscalation: You aren't an administrator for all departments for which this user is an administrator.
|
||||
UnauthorizedExamOffice: You are not part of an exam office.
|
||||
UnauthorizedExamExamOffice: You are not part of the appropriate exam office for any of the participants of this exam.
|
||||
UnauthorizedExternalExamExamOffice: You are not part of the appropriate exam office for any of the participants of this exam.
|
||||
UnauthorizedSchoolLecturer: You are no lecturer for this department.
|
||||
UnauthorizedLecturer: You are no administrator for this course.
|
||||
UnauthorizedAllocationLecturer: You are no administrator for any of the courses of this central allocation.
|
||||
@ -449,6 +450,7 @@ UnauthorizedTutorialRegisterGroup: You are already registered for a tutorial wit
|
||||
UnauthorizedLDAP: Specified user does not log in with their campus account.
|
||||
UnauthorizedPWHash: Specified user does not log in with an Uni2work-account.
|
||||
UnauthorizedExternalExamListNotEmpty: List of external exams is not empty
|
||||
UnauthorizedExternalExamLecturer: You are not an associated person for this external exam
|
||||
|
||||
UnauthorizedPasswordResetToken: This authorisation-token may no longer be used to change passwords
|
||||
|
||||
@ -2217,3 +2219,26 @@ Deficit: Deficit
|
||||
MetricNoSamples: No samples
|
||||
MetricName: Name
|
||||
MetricValue: Value
|
||||
|
||||
ExternalExamSemester: Semester
|
||||
ExternalExamSchool: Department
|
||||
ExternalExamCourseName: Course
|
||||
ExternalExamCourseNameTip: Needs only be unique among within semester and department.
|
||||
ExternalExamCourseNamePlaceholder: Analysis I, Programming and Modelling, ...
|
||||
ExternalExamExamName: Exam title
|
||||
ExternalExamExamNameTip: Needs only be unique within the course.
|
||||
ExternalExamExamNamePlaceholder: Exam, Exam resit, Project discussion, ...
|
||||
ExternalExamDefaultTime: Default time
|
||||
ExternalExamDefaultTimePlaceholder: Time
|
||||
ExternalExamDefaultTimeTip: The time of the exam needs to be specified for each participant. The time entered here is used as a default value for participants for whom no different time is later specified.
|
||||
ExternalExamShowGrades: Exam is graded
|
||||
ExternalExamShowGradesTip: Should participants and relevant exam offices be show exact grades or only whether the exam was passed or failed?
|
||||
ExternalExamExamOfficeSchools: Additional departments
|
||||
ExternalExamExamOfficeSchoolsTip: Exam offices of departments you specify here will also have full access to all results for this exam disregarding the individual participants' features of study.
|
||||
ExternalExamStaff: Associated persons
|
||||
ExternalExamStaffTip: The list of ssociated persons is shown to exam offices and participants. Additionally associated persons may upload results for the exam.
|
||||
ExternalExamStaffAlreadyAdded: Person is already associated with the exam.
|
||||
ExternalExamUserMustBeStaff: You yourself must always be an associated person for exams you create.
|
||||
ExternalExamCourseExists: This course already exists with uni2work. Exams for courses that exist within uni2work should be associated with the course directly instead of being created as an external exam.
|
||||
ExternalExamExists coursen@CourseName examn@ExamName: Exam “#{examn}” already exists for course “#{coursen}”.
|
||||
ExternalExamCreated coursen@CourseName examn@ExamName: Succesfully created exam “#{examn}” for course “#{coursen}”.
|
||||
|
||||
@ -4,6 +4,8 @@ module Handler.ExternalExam.Edit
|
||||
|
||||
import Import
|
||||
|
||||
import Handler.ExternalExam.Form ()
|
||||
|
||||
|
||||
getEEEditR, postEEEditR :: TermId -> SchoolId -> CourseName -> ExamName -> Handler Html
|
||||
getEEEditR = postEEEditR
|
||||
|
||||
115
src/Handler/ExternalExam/Form.hs
Normal file
115
src/Handler/ExternalExam/Form.hs
Normal file
@ -0,0 +1,115 @@
|
||||
module Handler.ExternalExam.Form
|
||||
( ExternalExamForm(..)
|
||||
, externalExamForm
|
||||
) where
|
||||
|
||||
import Import
|
||||
import Handler.Utils
|
||||
|
||||
import Handler.ExternalExam.StaffInvite ()
|
||||
|
||||
import qualified Data.Set as Set
|
||||
import Data.Map ((!))
|
||||
|
||||
import qualified Control.Monad.State.Class as State
|
||||
|
||||
|
||||
data ExternalExamForm = ExternalExamForm
|
||||
{ eefTerm :: TermId
|
||||
, eefSchool :: SchoolId
|
||||
, eefCourseName :: CI Text
|
||||
, eefExamName :: CI Text
|
||||
, eefDefaultTime :: Maybe UTCTime
|
||||
, eefShowGrades :: Bool
|
||||
, eefOfficeSchools :: Set SchoolId
|
||||
, eefStaff :: Set (Either UserEmail UserId)
|
||||
}
|
||||
|
||||
makeLenses_ ''ExternalExamForm
|
||||
|
||||
externalExamForm :: Maybe ExternalExamForm -> Form ExternalExamForm
|
||||
externalExamForm template = validateForm validateExternalExam $ \html -> do
|
||||
uid <- requireAuthId
|
||||
cRoute <- fromMaybe (error "tutorialForm called from 404-Handler") <$> getCurrentRoute
|
||||
MsgRenderer mr <- getMsgRenderer
|
||||
|
||||
let termsField = case template of
|
||||
Just template' -> termsSetField [eefTerm template']
|
||||
_other -> termsAllowedField
|
||||
|
||||
(lecturerSchools, adminSchools, oldSchool) <- liftHandler . runDB $ do
|
||||
lecturerSchools <- map (userFunctionSchool . entityVal) <$> selectList [UserFunctionUser ==. uid, UserFunctionFunction <-. [SchoolLecturer]] []
|
||||
protoAdminSchools <- map (userFunctionSchool . entityVal) <$> selectList [UserFunctionUser ==. uid, UserFunctionFunction <-. [SchoolAdmin]] []
|
||||
adminSchools <- filterM (hasWriteAccessTo . flip SchoolR SchoolEditR) protoAdminSchools
|
||||
let oldSchool = eefSchool <$> template
|
||||
return (lecturerSchools, adminSchools, oldSchool)
|
||||
let userSchools = nub . maybe id (:) oldSchool $ lecturerSchools ++ adminSchools
|
||||
|
||||
flip (renderAForm FormStandard) html $ ExternalExamForm
|
||||
<$> areq termsField (fslI MsgExternalExamSemester) (eefTerm <$> template)
|
||||
<*> areq (schoolFieldFor userSchools) (fslI MsgExternalExamSchool) (eefSchool <$> template)
|
||||
<*> areq (textField & cfStrip & cfCI) (fslI MsgExternalExamCourseName & setTooltip MsgExternalExamCourseNameTip & addPlaceholder (mr MsgExternalExamCourseNamePlaceholder)) (eefCourseName <$> template)
|
||||
<*> areq (textField & cfStrip & cfCI) (fslI MsgExternalExamExamName & setTooltip MsgExternalExamExamNameTip & addPlaceholder (mr MsgExternalExamExamNamePlaceholder)) (eefExamName <$> template)
|
||||
<*> aopt utcTimeField (fslI MsgExternalExamDefaultTime & setTooltip MsgExternalExamDefaultTimeTip & addPlaceholder (mr MsgExternalExamDefaultTimePlaceholder)) (eefDefaultTime <$> template)
|
||||
<*> apopt checkBoxField (fslI MsgExternalExamShowGrades & setTooltip MsgExternalExamShowGradesTip) (eefShowGrades <$> template)
|
||||
<*> (Set.fromList <$> officeSchoolForm cRoute (Set.toList . eefOfficeSchools <$> template))
|
||||
<*> (Set.fromList <$> staffForm cRoute ((Set.toList . eefStaff <$> template) <|> pure (pure $ Right uid)))
|
||||
where
|
||||
officeSchoolForm cRoute = massInputAccumA miAdd miCell miButtonAction miLayout miIdent fSettings fRequired
|
||||
where
|
||||
miAdd mkUnique submitView csrf = do
|
||||
(schoolRes, addView) <- mpopt schoolField ("" & addName (mkUnique "school")) Nothing
|
||||
let schoolRes' = schoolRes <&> \newDat oldDat -> FormSuccess (guardOn (newDat `notElem` oldDat) newDat)
|
||||
return (schoolRes', $(widgetFile "external-exam/schoolMassInput/add"))
|
||||
miCell ssh = do
|
||||
School{..} <- liftHandler . runDB $ getJust ssh
|
||||
$(widgetFile "external-exam/schoolMassInput/cell")
|
||||
miButtonAction :: forall p. PathPiece p => p -> Maybe (SomeRoute UniWorX)
|
||||
miButtonAction = Just . SomeRoute . (cRoute :#:)
|
||||
miLayout :: MassInputLayout ListLength SchoolId ()
|
||||
miLayout lLength _ cellWdgts delButtons addWdgts = $(widgetFile "external-exam/schoolMassInput/layout")
|
||||
miIdent :: Text
|
||||
miIdent = "external-exams-school"
|
||||
fSettings = fslI MsgExternalExamExamOfficeSchools & setTooltip (UniWorXMessages [SomeMessage MsgExternalExamExamOfficeSchoolsTip, SomeMessage MsgMassInputTip])
|
||||
fRequired = False
|
||||
staffForm cRoute = massInputAccumA miAdd miCell miButtonAction miLayout miIdent fSettings fRequired
|
||||
where
|
||||
miAdd mkUnique submitView csrf = do
|
||||
MsgRenderer mr <- getMsgRenderer
|
||||
(usersRes, addView) <- mpreq (multiUserField False Nothing) ("" & addName (mkUnique "email")) Nothing
|
||||
let
|
||||
usersRes' = usersRes <&> \newDat oldDat -> if
|
||||
| existing <- newDat `Set.intersection` Set.fromList oldDat
|
||||
, not $ Set.null existing
|
||||
-> FormFailure [mr MsgExternalExamStaffAlreadyAdded]
|
||||
| otherwise
|
||||
-> FormSuccess $ Set.toList newDat
|
||||
return (usersRes', $(widgetFile "external-exam/staffMassInput/add"))
|
||||
miCell (Left email) = do
|
||||
invWarnMsg <- messageI Warning MsgEmailInvitationWarning
|
||||
$(widgetFile "external-exam/staffMassInput/cellInvitation")
|
||||
miCell (Right userId) = do
|
||||
User{..} <- liftHandler . runDB $ getJust userId
|
||||
$(widgetFile "external-exam/staffMassInput/cellKnown")
|
||||
miButtonAction :: forall p. PathPiece p => p -> Maybe (SomeRoute UniWorX)
|
||||
miButtonAction = Just . SomeRoute . (cRoute :#:)
|
||||
miLayout :: MassInputLayout ListLength (Either UserEmail UserId) ()
|
||||
miLayout lLength _ cellWdgts delButtons addWdgts = $(widgetFile "external-exam/staffMassInput/layout")
|
||||
miIdent :: Text
|
||||
miIdent = "external-exams-staff"
|
||||
fSettings = fslI MsgExternalExamStaff & setTooltip (UniWorXMessages [SomeMessage MsgExternalExamStaffTip, SomeMessage MsgMassInputTip])
|
||||
fRequired = True
|
||||
|
||||
validateExternalExam :: (MonadThrow m, MonadHandler m, HandlerSite m ~ UniWorX) => FormValidator ExternalExamForm m ()
|
||||
validateExternalExam = do
|
||||
State.modify $ \eeForm -> eeForm & over _eefOfficeSchools (Set.delete $ eeForm ^. _eefSchool)
|
||||
|
||||
ExternalExamForm{..} <- State.get
|
||||
|
||||
isAdmin <- hasWriteAccessTo $ SchoolR eefSchool SchoolEditR
|
||||
unless isAdmin $ do
|
||||
uid <- requireAuthId
|
||||
guardValidation MsgExternalExamUserMustBeStaff $ Right uid `Set.member` eefStaff
|
||||
|
||||
courseExists <- liftHandler . runDB . existsBy $ TermSchoolCourseName eefTerm eefSchool eefCourseName
|
||||
guardValidation MsgExternalExamCourseExists $ not courseExists
|
||||
@ -4,7 +4,59 @@ module Handler.ExternalExam.New
|
||||
|
||||
import Import
|
||||
|
||||
import Jobs.Queue
|
||||
|
||||
import Handler.Utils
|
||||
import Handler.Utils.Invitations
|
||||
|
||||
import Handler.ExternalExam.StaffInvite
|
||||
import Handler.ExternalExam.Form
|
||||
|
||||
import qualified Data.Set as Set
|
||||
|
||||
|
||||
getEExamNewR, postEExamNewR :: Handler Html
|
||||
getEExamNewR = postEExamNewR
|
||||
postEExamNewR = error "Not implemented"
|
||||
postEExamNewR = do
|
||||
((newExamResult, newExamWidget'), newExamEnctype) <- runFormPost $ externalExamForm Nothing
|
||||
|
||||
formResult newExamResult $ \ExternalExamForm{..} -> do
|
||||
insertRes <- runDBJobs $ do
|
||||
insertRes <- insertUnique ExternalExam
|
||||
{ externalExamTerm = eefTerm
|
||||
, externalExamSchool = eefSchool
|
||||
, externalExamCourseName = eefCourseName
|
||||
, externalExamExamName = eefExamName
|
||||
, externalExamDefaultTime = eefDefaultTime
|
||||
, externalExamShowGrades = eefShowGrades
|
||||
}
|
||||
whenIsJust insertRes $ \eeId -> do
|
||||
insertMany_
|
||||
[ ExternalExamOfficeSchool{..}
|
||||
| externalExamOfficeSchoolSchool <- Set.toList eefOfficeSchools
|
||||
, externalExamOfficeSchoolSchool /= eefSchool
|
||||
, let externalExamOfficeSchoolExam = eeId
|
||||
]
|
||||
|
||||
let (invites, adds) = partitionEithers $ Set.toList eefStaff
|
||||
insertMany_ [ ExternalExamStaff{..}
|
||||
| externalExamStaffUser <- adds
|
||||
, let externalExamStaffExam = eeId
|
||||
]
|
||||
sinkInvitationsF externalExamStaffInvitationConfig $ map (, eeId, (InvDBDataExternalExamStaff, InvTokenDataExternalExamStaff)) invites
|
||||
return insertRes
|
||||
|
||||
case insertRes of
|
||||
Nothing -> addMessageI Error $ MsgExternalExamExists eefCourseName eefExamName
|
||||
Just _ -> do
|
||||
addMessageI Success $ MsgExternalExamCreated eefCourseName eefExamName
|
||||
redirect $ EExamR eefTerm eefSchool eefCourseName eefExamName EEShowR
|
||||
|
||||
let heading = MsgMenuExternalExamNew
|
||||
|
||||
siteLayoutMsg heading $ do
|
||||
setTitleI heading
|
||||
wrapForm newExamWidget' def
|
||||
{ formAction = Just $ SomeRoute EExamNewR
|
||||
, formEncoding = newExamEnctype
|
||||
}
|
||||
|
||||
6
templates/external-exam/schoolMassInput/add.hamlet
Normal file
6
templates/external-exam/schoolMassInput/add.hamlet
Normal file
@ -0,0 +1,6 @@
|
||||
$newline never
|
||||
<td>
|
||||
#{csrf}
|
||||
^{fvInput addView}
|
||||
<td>
|
||||
^{fvInput submitView}
|
||||
3
templates/external-exam/schoolMassInput/cell.hamlet
Normal file
3
templates/external-exam/schoolMassInput/cell.hamlet
Normal file
@ -0,0 +1,3 @@
|
||||
$newline never
|
||||
<td>
|
||||
#{schoolName}
|
||||
11
templates/external-exam/schoolMassInput/layout.hamlet
Normal file
11
templates/external-exam/schoolMassInput/layout.hamlet
Normal file
@ -0,0 +1,11 @@
|
||||
$newline never
|
||||
<table>
|
||||
<tbody>
|
||||
$forall coord <- review liveCoords lLength
|
||||
<tr .massinput__cell>
|
||||
^{cellWdgts ! coord}
|
||||
<td>
|
||||
^{fvInput (delButtons ! coord)}
|
||||
<tfoot>
|
||||
<tr .massinput__cell.massinput__cell--add>
|
||||
^{addWdgts ! (0, 0)}
|
||||
6
templates/external-exam/staffMassInput/add.hamlet
Normal file
6
templates/external-exam/staffMassInput/add.hamlet
Normal file
@ -0,0 +1,6 @@
|
||||
$newline never
|
||||
<td colspan=2>
|
||||
#{csrf}
|
||||
^{fvInput addView}
|
||||
<td>
|
||||
^{fvInput submitView}
|
||||
@ -0,0 +1,6 @@
|
||||
$newline never
|
||||
<td>
|
||||
<span style="font-family: monospace">
|
||||
#{email}
|
||||
<td>
|
||||
^{messageTooltip invWarnMsg}
|
||||
3
templates/external-exam/staffMassInput/cellKnown.hamlet
Normal file
3
templates/external-exam/staffMassInput/cellKnown.hamlet
Normal file
@ -0,0 +1,3 @@
|
||||
$newline never
|
||||
<td colspan=2>
|
||||
^{nameEmailWidget userEmail userDisplayName userSurname}
|
||||
11
templates/external-exam/staffMassInput/layout.hamlet
Normal file
11
templates/external-exam/staffMassInput/layout.hamlet
Normal file
@ -0,0 +1,11 @@
|
||||
$newline never
|
||||
<table>
|
||||
<tbody>
|
||||
$forall coord <- review liveCoords lLength
|
||||
<tr .massinput__cell>
|
||||
^{cellWdgts ! coord}
|
||||
<td>
|
||||
^{fvInput (delButtons ! coord)}
|
||||
<tfoot>
|
||||
<tr .massinput__cell.massinput__cell--add>
|
||||
^{addWdgts ! (0, 0)}
|
||||
Loading…
Reference in New Issue
Block a user