feat(external-exams): requisite routes
This commit is contained in:
parent
e4393972f8
commit
f25b21aa4b
@ -403,6 +403,7 @@ UnauthorizedSchoolAdmin: Sie sind nicht als Administrator für dieses Institut e
|
|||||||
UnauthorizedAdminEscalation: Sie sind nicht Administrator für alle Institute, für die dieser Nutzer Administrator oder Veranstalter ist.
|
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.
|
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.
|
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.
|
||||||
UnauthorizedSchoolLecturer: Sie sind nicht als Veranstalter für dieses Institut eingetragen.
|
UnauthorizedSchoolLecturer: Sie sind nicht als Veranstalter für dieses Institut eingetragen.
|
||||||
UnauthorizedLecturer: Sie sind nicht als Veranstalter für diese Veranstaltung 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.
|
UnauthorizedAllocationLecturer: Sie sind nicht als Veranstalter für eine Veranstaltung dieser Zentralanmeldung eingetragen.
|
||||||
@ -449,6 +450,8 @@ UnauthorizedTutor: Sie sind nicht Tutor.
|
|||||||
UnauthorizedTutorialRegisterGroup: Sie sind bereits in einem Tutorium mit derselben Registrierungs-Gruppe.
|
UnauthorizedTutorialRegisterGroup: Sie sind bereits in einem Tutorium mit derselben Registrierungs-Gruppe.
|
||||||
UnauthorizedLDAP: Angegebener Nutzer meldet sich nicht mit Campus-Kennung an.
|
UnauthorizedLDAP: Angegebener Nutzer meldet sich nicht mit Campus-Kennung an.
|
||||||
UnauthorizedPWHash: Angegebener Nutzer meldet sich nicht mit Uni2work-Kennung an.
|
UnauthorizedPWHash: Angegebener Nutzer meldet sich nicht mit Uni2work-Kennung an.
|
||||||
|
UnauthorizedExternalExamListNotEmpty: Liste von externen Prüfungen ist nicht leer
|
||||||
|
UnauthorizedExternalExamLecturer: Sie sind nicht als Prüfer für diese externe Prüfung eingetragen
|
||||||
|
|
||||||
UnauthorizedPasswordResetToken: Dieses Authorisierungs-Token kann nicht mehr zum Passwort ändern benutzt werden
|
UnauthorizedPasswordResetToken: Dieses Authorisierungs-Token kann nicht mehr zum Passwort ändern benutzt werden
|
||||||
|
|
||||||
@ -1190,6 +1193,11 @@ MenuCourseNewsNew: Neue Kursnachricht
|
|||||||
MenuCourseNewsEdit: Kursnachricht bearbeiten
|
MenuCourseNewsEdit: Kursnachricht bearbeiten
|
||||||
MenuCourseEventNew: Neuer Kurstermin
|
MenuCourseEventNew: Neuer Kurstermin
|
||||||
MenuCourseEventEdit: Kurstermin bearbeiten
|
MenuCourseEventEdit: Kurstermin bearbeiten
|
||||||
|
MenuExternalExamGrades: Prüfungsleistungen
|
||||||
|
MenuExternalExamUsers: Teilnehmer
|
||||||
|
MenuExternalExamEdit: Bearbeiten
|
||||||
|
MenuExternalExamNew: Neue externe Prüfung
|
||||||
|
MenuExternalExamList: Externe Prüfungen
|
||||||
|
|
||||||
BreadcrumbSubmissionFile: Datei
|
BreadcrumbSubmissionFile: Datei
|
||||||
BreadcrumbSubmissionUserInvite: Einladung zur Abgabe
|
BreadcrumbSubmissionUserInvite: Einladung zur Abgabe
|
||||||
@ -1242,6 +1250,13 @@ BreadcrumbExamRegister: Anmelden
|
|||||||
BreadcrumbApplicationFiles: Bewerbungsdateien
|
BreadcrumbApplicationFiles: Bewerbungsdateien
|
||||||
BreadcrumbCourseNewsArchive: Archiv
|
BreadcrumbCourseNewsArchive: Archiv
|
||||||
BreadcrumbCourseNewsFile: Datei
|
BreadcrumbCourseNewsFile: Datei
|
||||||
|
BreadcrumbExternalExam: Externe Prüfung
|
||||||
|
BreadcrumbExternalExamList: Externe Prüfungen
|
||||||
|
BreadcrumbExternalExamNew: Neue externe Prüfung
|
||||||
|
BreadcrumbExternalExamShow coursen@CourseName examn@ExamName: #{coursen}, #{examn}
|
||||||
|
BreadcrumbExternalExamEdit: Editieren
|
||||||
|
BreadcrumbExternalExamUsers: Teilnehmer
|
||||||
|
BreadcrumbExternalExamGrades: Prüfungsleistungen
|
||||||
|
|
||||||
TitleMetrics: Metriken
|
TitleMetrics: Metriken
|
||||||
|
|
||||||
|
|||||||
@ -447,6 +447,7 @@ UnauthorizedTutor: You are no tutor.
|
|||||||
UnauthorizedTutorialRegisterGroup: You are already registered for a tutorial with the same registration group.
|
UnauthorizedTutorialRegisterGroup: You are already registered for a tutorial with the same registration group.
|
||||||
UnauthorizedLDAP: Specified user does not log in with their campus account.
|
UnauthorizedLDAP: Specified user does not log in with their campus account.
|
||||||
UnauthorizedPWHash: Specified user does not log in with an Uni2work-account.
|
UnauthorizedPWHash: Specified user does not log in with an Uni2work-account.
|
||||||
|
UnauthorizedExternalExamListNotEmpty: List of external exams is not empty
|
||||||
|
|
||||||
UnauthorizedPasswordResetToken: This authorisation-token may no longer be used to change passwords
|
UnauthorizedPasswordResetToken: This authorisation-token may no longer be used to change passwords
|
||||||
|
|
||||||
@ -1189,6 +1190,11 @@ MenuCourseNewsNew: Add course news
|
|||||||
MenuCourseNewsEdit: Edit course news
|
MenuCourseNewsEdit: Edit course news
|
||||||
MenuCourseEventNew: New course occurrence
|
MenuCourseEventNew: New course occurrence
|
||||||
MenuCourseEventEdit: Edit course occurrence
|
MenuCourseEventEdit: Edit course occurrence
|
||||||
|
MenuExternalExamGrades: Exam results
|
||||||
|
MenuExternalExamUsers: Participants
|
||||||
|
MenuExternalExamEdit: Edit
|
||||||
|
MenuExternalExamNew: New external exam
|
||||||
|
MenuExternalExamList: External exams
|
||||||
|
|
||||||
BreadcrumbSubmissionFile: File
|
BreadcrumbSubmissionFile: File
|
||||||
BreadcrumbSubmissionUserInvite: Invitation to participate in a submission
|
BreadcrumbSubmissionUserInvite: Invitation to participate in a submission
|
||||||
@ -1241,6 +1247,13 @@ BreadcrumbExamRegister: Register
|
|||||||
BreadcrumbApplicationFiles: Application files
|
BreadcrumbApplicationFiles: Application files
|
||||||
BreadcrumbCourseNewsArchive: Archive
|
BreadcrumbCourseNewsArchive: Archive
|
||||||
BreadcrumbCourseNewsFile: File
|
BreadcrumbCourseNewsFile: File
|
||||||
|
BreadcrumbExternalExam: External exam
|
||||||
|
BreadcrumbExternalExamList: External exams
|
||||||
|
BreadcrumbExternalExamNew: New external exam
|
||||||
|
BreadcrumbExternalExamShow coursen@CourseName examn@ExamName: #{coursen}, #{examn}
|
||||||
|
BreadcrumbExternalExamEdit: Edit
|
||||||
|
BreadcrumbExternalExamUsers: Participants
|
||||||
|
BreadcrumbExternalExamGrades: Exam results
|
||||||
|
|
||||||
TitleMetrics: Metrics
|
TitleMetrics: Metrics
|
||||||
|
|
||||||
|
|||||||
@ -12,3 +12,8 @@ ExamOfficeResultSynced
|
|||||||
office UserId
|
office UserId
|
||||||
result ExamResultId
|
result ExamResultId
|
||||||
time UTCTime
|
time UTCTime
|
||||||
|
ExamOfficeExternalResultSynced
|
||||||
|
school SchoolId Maybe
|
||||||
|
office UserId
|
||||||
|
result ExternalExamResultId
|
||||||
|
time UTCTime
|
||||||
23
models/external-exams.model
Normal file
23
models/external-exams.model
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
ExternalExam
|
||||||
|
term TermId
|
||||||
|
school SchoolId
|
||||||
|
courseName (CI Text)
|
||||||
|
examName (CI Text)
|
||||||
|
defaultTime UTCTime Maybe
|
||||||
|
showGrades Bool
|
||||||
|
UniqueExternalExam term school courseName examName
|
||||||
|
ExternalExamResult
|
||||||
|
user UserId
|
||||||
|
exam ExternalExamId
|
||||||
|
result ExamResultGrade
|
||||||
|
time UTCTime
|
||||||
|
lastChanged UTCTime
|
||||||
|
UniqueExternalExamResult exam user
|
||||||
|
ExternalExamStaff
|
||||||
|
user UserId
|
||||||
|
exam ExternalExamId
|
||||||
|
UniqueExternalExamStaff exam user
|
||||||
|
ExternalExamOfficeSchool
|
||||||
|
school SchoolId
|
||||||
|
exam ExternalExamId
|
||||||
|
UniqueExternalExamOfficeSchool exam school
|
||||||
9
routes
9
routes
@ -80,6 +80,15 @@
|
|||||||
/users EOUsersR GET POST
|
/users EOUsersR GET POST
|
||||||
/users/invite EOUsersInviteR GET POST
|
/users/invite EOUsersInviteR GET POST
|
||||||
|
|
||||||
|
/external-exam EExamListR GET !lecturer !¬empty
|
||||||
|
/external-exam/new EExamNewR GET POST !lecturer
|
||||||
|
/external-exam/#TermId/#SchoolId/#CourseName/#ExamName EExamR !lecturer:
|
||||||
|
/ EEShowR GET !exam-office
|
||||||
|
/edit EEEditR GET POST
|
||||||
|
/users EEUsersR GET POST
|
||||||
|
/grades EEGradesR GET POST !exam-office
|
||||||
|
|
||||||
|
|
||||||
/term TermShowR GET !free
|
/term TermShowR GET !free
|
||||||
/term/current TermCurrentR GET !free
|
/term/current TermCurrentR GET !free
|
||||||
/term/edit TermEditR GET POST
|
/term/edit TermEditR GET POST
|
||||||
|
|||||||
@ -122,6 +122,7 @@ import Handler.Exam
|
|||||||
import Handler.Allocation
|
import Handler.Allocation
|
||||||
import Handler.ExamOffice
|
import Handler.ExamOffice
|
||||||
import Handler.Metrics
|
import Handler.Metrics
|
||||||
|
import Handler.ExternalExam
|
||||||
|
|
||||||
|
|
||||||
-- This line actually creates our YesodDispatch instance. It is the second half
|
-- This line actually creates our YesodDispatch instance. It is the second half
|
||||||
|
|||||||
@ -69,6 +69,7 @@ import qualified Control.Monad.Catch as C
|
|||||||
import Handler.Utils.StudyFeatures
|
import Handler.Utils.StudyFeatures
|
||||||
import Handler.Utils.SchoolLdap
|
import Handler.Utils.SchoolLdap
|
||||||
import Handler.Utils.ExamOffice.Exam
|
import Handler.Utils.ExamOffice.Exam
|
||||||
|
import Handler.Utils.ExamOffice.ExternalExam
|
||||||
import Handler.Utils.ExamOffice.Course
|
import Handler.Utils.ExamOffice.Course
|
||||||
import Handler.Utils.Profile
|
import Handler.Utils.Profile
|
||||||
import Handler.Utils.Routes
|
import Handler.Utils.Routes
|
||||||
@ -371,6 +372,19 @@ tagAccessPredicate AuthExamOffice = APDB $ \mAuthId route _ -> case route of
|
|||||||
E.where_ $ examOfficeExamResultAuth (E.val authId) examResult
|
E.where_ $ examOfficeExamResultAuth (E.val authId) examResult
|
||||||
guardMExceptT hasUsers (unauthorizedI MsgUnauthorizedExamExamOffice)
|
guardMExceptT hasUsers (unauthorizedI MsgUnauthorizedExamExamOffice)
|
||||||
return Authorized
|
return Authorized
|
||||||
|
EExamR tid ssh coursen examn _ -> $cachedHereBinary (mAuthId, tid, ssh, coursen, examn) . exceptT return return $ do
|
||||||
|
authId <- maybeExceptT AuthenticationRequired $ return mAuthId
|
||||||
|
hasUsers <- lift . E.selectExists . E.from $ \(eexam `E.InnerJoin` eexamResult) -> do
|
||||||
|
E.on $ eexam E.^. ExternalExamId E.==. eexamResult E.^. ExternalExamResultExam
|
||||||
|
|
||||||
|
E.where_ $ eexam E.^. ExternalExamTerm E.==. E.val tid
|
||||||
|
E.&&. eexam E.^. ExternalExamSchool E.==. E.val ssh
|
||||||
|
E.&&. eexam E.^. ExternalExamCourseName E.==. E.val coursen
|
||||||
|
E.&&. eexam E.^. ExternalExamExamName E.==. E.val examn
|
||||||
|
|
||||||
|
E.where_ $ examOfficeExternalExamResultAuth (E.val authId) eexamResult
|
||||||
|
guardMExceptT hasUsers $ unauthorizedI MsgUnauthorizedExternalExamExamOffice
|
||||||
|
return Authorized
|
||||||
_other -> $cachedHereBinary mAuthId . exceptT return return $ do
|
_other -> $cachedHereBinary mAuthId . exceptT return return $ do
|
||||||
authId <- maybeExceptT AuthenticationRequired $ return mAuthId
|
authId <- maybeExceptT AuthenticationRequired $ return mAuthId
|
||||||
adrights <- lift $ selectFirst [UserFunctionUser ==. authId, UserFunctionFunction ==. SchoolExamOffice] []
|
adrights <- lift $ selectFirst [UserFunctionUser ==. authId, UserFunctionFunction ==. SchoolExamOffice] []
|
||||||
@ -420,7 +434,18 @@ tagAccessPredicate AuthLecturer = APDB $ \mAuthId route _ -> case route of
|
|||||||
E.&&. allocation E.^. AllocationTerm E.==. E.val tid
|
E.&&. allocation E.^. AllocationTerm E.==. E.val tid
|
||||||
E.&&. allocation E.^. AllocationSchool E.==. E.val ssh
|
E.&&. allocation E.^. AllocationSchool E.==. E.val ssh
|
||||||
E.&&. allocation E.^. AllocationShorthand E.==. E.val ash
|
E.&&. allocation E.^. AllocationShorthand E.==. E.val ash
|
||||||
guardMExceptT isLecturer (unauthorizedI MsgUnauthorizedAllocationLecturer)
|
guardMExceptT isLecturer $ unauthorizedI MsgUnauthorizedAllocationLecturer
|
||||||
|
return Authorized
|
||||||
|
EExamR tid ssh coursen examn _ -> $cachedHereBinary (mAuthId, tid, ssh, coursen, examn) . exceptT return return $ do
|
||||||
|
authId <- maybeExceptT AuthenticationRequired $ return mAuthId
|
||||||
|
isLecturer <- lift . E.selectExists . E.from $ \(eexam `E.InnerJoin` staff) -> do
|
||||||
|
E.on $ eexam E.^. ExternalExamId E.==. staff E.^. ExternalExamStaffExam
|
||||||
|
E.where_ $ staff E.^. ExternalExamStaffUser E.==. E.val authId
|
||||||
|
E.&&. eexam E.^. ExternalExamTerm E.==. E.val tid
|
||||||
|
E.&&. eexam E.^. ExternalExamSchool E.==. E.val ssh
|
||||||
|
E.&&. eexam E.^. ExternalExamCourseName E.==. E.val coursen
|
||||||
|
E.&&. eexam E.^. ExternalExamExamName E.==. E.val examn
|
||||||
|
guardMExceptT isLecturer $ unauthorizedI MsgUnauthorizedExternalExamLecturer
|
||||||
return Authorized
|
return Authorized
|
||||||
-- lecturer for any school will do
|
-- lecturer for any school will do
|
||||||
_ -> $cachedHereBinary mAuthId . exceptT return return $ do
|
_ -> $cachedHereBinary mAuthId . exceptT return return $ do
|
||||||
@ -1033,7 +1058,14 @@ tagAccessPredicate AuthRegisterGroup = APDB $ \mAuthId route _ -> case route of
|
|||||||
guard $ not hasOther
|
guard $ not hasOther
|
||||||
return Authorized
|
return Authorized
|
||||||
r -> $unsupportedAuthPredicate AuthRegisterGroup r
|
r -> $unsupportedAuthPredicate AuthRegisterGroup r
|
||||||
tagAccessPredicate AuthEmpty = APDB $ \_ route _ -> case route of
|
tagAccessPredicate AuthEmpty = APDB $ \mAuthId route _ -> case route of
|
||||||
|
EExamListR -> exceptT return return $ do
|
||||||
|
authId <- maybeExceptT AuthenticationRequired $ return mAuthId
|
||||||
|
hasExternalExams <- $cachedHereBinary authId . lift . E.selectExists . E.from $ \(eexam `E.InnerJoin` eexamStaff) -> do
|
||||||
|
E.on $ eexam E.^. ExternalExamId E.==. eexamStaff E.^. ExternalExamStaffExam
|
||||||
|
E.where_ $ eexamStaff E.^. ExternalExamStaffUser E.==. E.val authId
|
||||||
|
guardMExceptT (not hasExternalExams) $ unauthorizedI MsgUnauthorizedExternalExamListNotEmpty
|
||||||
|
return Authorized
|
||||||
CourseR tid ssh csh _ -> maybeT (unauthorizedI MsgCourseNotEmpty) $ do
|
CourseR tid ssh csh _ -> maybeT (unauthorizedI MsgCourseNotEmpty) $ do
|
||||||
-- Entity cid Course{..} <- MaybeT . getBy $ TermSchoolCourseShort tid ssh csh
|
-- Entity cid Course{..} <- MaybeT . getBy $ TermSchoolCourseShort tid ssh csh
|
||||||
cid <- $cachedHereBinary (tid, ssh, csh) . MaybeT . getKeyBy $ TermSchoolCourseShort tid ssh csh
|
cid <- $cachedHereBinary (tid, ssh, csh) . MaybeT . getKeyBy $ TermSchoolCourseShort tid ssh csh
|
||||||
@ -1500,8 +1532,9 @@ siteLayout' headingOverride widget = do
|
|||||||
where
|
where
|
||||||
go crumbs Nothing = return crumbs
|
go crumbs Nothing = return crumbs
|
||||||
go crumbs (Just cRoute) = do
|
go crumbs (Just cRoute) = do
|
||||||
|
hasAccess <- hasReadAccessTo cRoute
|
||||||
(title, next) <- breadcrumb cRoute
|
(title, next) <- breadcrumb cRoute
|
||||||
go ((cRoute, title) : crumbs) next
|
go ((cRoute, title, hasAccess) : crumbs) next
|
||||||
(title, parents) <- breadcrumbs' mcurrentRoute
|
(title, parents) <- breadcrumbs' mcurrentRoute
|
||||||
|
|
||||||
-- let isParent :: Route UniWorX -> Bool
|
-- let isParent :: Route UniWorX -> Bool
|
||||||
@ -1588,7 +1621,7 @@ siteLayout' headingOverride widget = do
|
|||||||
}
|
}
|
||||||
|
|
||||||
let highlight :: Route UniWorX -> Bool -- highlight last route in breadcrumbs, favorites taking priority
|
let highlight :: Route UniWorX -> Bool -- highlight last route in breadcrumbs, favorites taking priority
|
||||||
highlight = let crumbs = mcons mcurrentRoute $ fst <$> reverse parents
|
highlight = let crumbs = mcons mcurrentRoute $ view _1 <$> reverse parents
|
||||||
navItems = map (view _2) favourites ++ map (urlRoute . menuItemRoute . view _1) menuTypes
|
navItems = map (view _2) favourites ++ map (urlRoute . menuItemRoute . view _1) menuTypes
|
||||||
highR = find (`elem` navItems) . uncurry (++) $ partition (`elem` map (view _2) favourites) crumbs
|
highR = find (`elem` navItems) . uncurry (++) $ partition (`elem` map (view _2) favourites) crumbs
|
||||||
in \r -> Just r == highR
|
in \r -> Just r == highR
|
||||||
@ -1933,6 +1966,25 @@ instance YesodBreadcrumbs UniWorX where
|
|||||||
breadcrumb MessageListR = i18nCrumb MsgMenuMessageList $ Just AdminR
|
breadcrumb MessageListR = i18nCrumb MsgMenuMessageList $ Just AdminR
|
||||||
|
|
||||||
breadcrumb GlossaryR = i18nCrumb MsgMenuGlossary $ Just InfoR
|
breadcrumb GlossaryR = i18nCrumb MsgMenuGlossary $ Just InfoR
|
||||||
|
|
||||||
|
breadcrumb EExamListR = i18nCrumb MsgMenuExternalExamList Nothing
|
||||||
|
breadcrumb EExamNewR = do
|
||||||
|
isEO <- hasReadAccessTo $ ExamOfficeR EOExamsR
|
||||||
|
i18nCrumb MsgBreadcrumbExternalExamNew . Just $ if
|
||||||
|
| isEO -> ExamOfficeR EOExamsR
|
||||||
|
| otherwise -> EExamListR
|
||||||
|
breadcrumb (EExamR tid ssh coursen examn sRoute) = case sRoute of
|
||||||
|
EEShowR -> do
|
||||||
|
isEO <- hasReadAccessTo $ ExamOfficeR EOExamsR
|
||||||
|
maybeT (i18nCrumb MsgBreadcrumbExternalExam . Just $ bool EExamListR (ExamOfficeR EOExamsR) isEO) $ do
|
||||||
|
guardM . hasReadAccessTo $ EExamR tid ssh coursen examn EEShowR
|
||||||
|
i18nCrumb (MsgBreadcrumbExternalExamShow coursen examn) . Just $ if
|
||||||
|
| isEO -> ExamOfficeR EOExamsR
|
||||||
|
| otherwise -> EExamListR
|
||||||
|
EEEditR -> i18nCrumb MsgBreadcrumbExternalExamEdit . Just $ EExamR tid ssh coursen examn EEShowR
|
||||||
|
EEUsersR -> i18nCrumb MsgBreadcrumbExternalExamUsers . Just $ EExamR tid ssh coursen examn EEShowR
|
||||||
|
EEGradesR -> i18nCrumb MsgBreadcrumbExternalExamGrades . Just $ EExamR tid ssh coursen examn EEShowR
|
||||||
|
|
||||||
-- breadcrumb _ = return ("Uni2work", Nothing) -- Default is no breadcrumb at all
|
-- breadcrumb _ = return ("Uni2work", Nothing) -- Default is no breadcrumb at all
|
||||||
|
|
||||||
submissionList :: TermId -> CourseShorthand -> SheetName -> UserId -> DB [E.Value SubmissionId]
|
submissionList :: TermId -> CourseShorthand -> SheetName -> UserId -> DB [E.Value SubmissionId]
|
||||||
@ -2119,6 +2171,14 @@ pageActions (HomeR) =
|
|||||||
, menuItemModal = False
|
, menuItemModal = False
|
||||||
, menuItemAccessCallback' = return True
|
, menuItemAccessCallback' = return True
|
||||||
}
|
}
|
||||||
|
, MenuItem
|
||||||
|
{ menuItemType = PageActionSecondary
|
||||||
|
, menuItemLabel = MsgMenuExternalExamList
|
||||||
|
, menuItemIcon = Nothing
|
||||||
|
, menuItemRoute = SomeRoute EExamListR
|
||||||
|
, menuItemModal = False
|
||||||
|
, menuItemAccessCallback' = return True
|
||||||
|
}
|
||||||
, MenuItem
|
, MenuItem
|
||||||
{ menuItemType = PageActionPrime
|
{ menuItemType = PageActionPrime
|
||||||
, menuItemLabel = MsgMenuOpenCourses
|
, menuItemLabel = MsgMenuOpenCourses
|
||||||
@ -3055,6 +3115,62 @@ pageActions (CorrectionsGradeR) =
|
|||||||
return $ orOf (traverse . _Value . _submissionModeCorrector) sheets
|
return $ orOf (traverse . _Value . _submissionModeCorrector) sheets
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
pageActions EExamListR =
|
||||||
|
[ MenuItem
|
||||||
|
{ menuItemType = PageActionPrime
|
||||||
|
, menuItemLabel = MsgMenuExternalExamNew
|
||||||
|
, menuItemIcon = Nothing
|
||||||
|
, menuItemRoute = SomeRoute EExamNewR
|
||||||
|
, menuItemModal = False
|
||||||
|
, menuItemAccessCallback' = return True
|
||||||
|
}
|
||||||
|
]
|
||||||
|
pageActions (EExamR tid ssh coursen examn EEShowR) =
|
||||||
|
[ MenuItem
|
||||||
|
{ menuItemType = PageActionPrime
|
||||||
|
, menuItemLabel = MsgMenuExternalExamEdit
|
||||||
|
, menuItemIcon = Nothing
|
||||||
|
, menuItemRoute = SomeRoute $ EExamR tid ssh coursen examn EEEditR
|
||||||
|
, menuItemModal = False
|
||||||
|
, menuItemAccessCallback' = return True
|
||||||
|
}
|
||||||
|
, MenuItem
|
||||||
|
{ menuItemType = PageActionPrime
|
||||||
|
, menuItemLabel = MsgMenuExternalExamUsers
|
||||||
|
, menuItemIcon = Nothing
|
||||||
|
, menuItemRoute = SomeRoute $ EExamR tid ssh coursen examn EEUsersR
|
||||||
|
, menuItemModal = False
|
||||||
|
, menuItemAccessCallback' = return True
|
||||||
|
}
|
||||||
|
, MenuItem
|
||||||
|
{ menuItemType = PageActionPrime
|
||||||
|
, menuItemLabel = MsgMenuExternalExamGrades
|
||||||
|
, menuItemIcon = Nothing
|
||||||
|
, menuItemRoute = SomeRoute $ EExamR tid ssh coursen examn EEGradesR
|
||||||
|
, menuItemModal = False
|
||||||
|
, menuItemAccessCallback' = return True
|
||||||
|
}
|
||||||
|
]
|
||||||
|
pageActions (EExamR tid ssh coursen examn EEGradesR) =
|
||||||
|
[ MenuItem
|
||||||
|
{ menuItemType = PageActionPrime
|
||||||
|
, menuItemLabel = MsgMenuExternalExamUsers
|
||||||
|
, menuItemIcon = Nothing
|
||||||
|
, menuItemRoute = SomeRoute $ EExamR tid ssh coursen examn EEUsersR
|
||||||
|
, menuItemModal = False
|
||||||
|
, menuItemAccessCallback' = return True
|
||||||
|
}
|
||||||
|
]
|
||||||
|
pageActions (EExamR tid ssh coursen examn EEUsersR) =
|
||||||
|
[ MenuItem
|
||||||
|
{ menuItemType = PageActionPrime
|
||||||
|
, menuItemLabel = MsgMenuExternalExamGrades
|
||||||
|
, menuItemIcon = Nothing
|
||||||
|
, menuItemRoute = SomeRoute $ EExamR tid ssh coursen examn EEGradesR
|
||||||
|
, menuItemModal = False
|
||||||
|
, menuItemAccessCallback' = return True
|
||||||
|
}
|
||||||
|
]
|
||||||
pageActions _ = []
|
pageActions _ = []
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -31,6 +31,7 @@ deriving instance Generic SubmissionR
|
|||||||
deriving instance Generic MaterialR
|
deriving instance Generic MaterialR
|
||||||
deriving instance Generic TutorialR
|
deriving instance Generic TutorialR
|
||||||
deriving instance Generic ExamR
|
deriving instance Generic ExamR
|
||||||
|
deriving instance Generic EExamR
|
||||||
deriving instance Generic CourseApplicationR
|
deriving instance Generic CourseApplicationR
|
||||||
deriving instance Generic AllocationR
|
deriving instance Generic AllocationR
|
||||||
deriving instance Generic SchoolR
|
deriving instance Generic SchoolR
|
||||||
|
|||||||
@ -6,3 +6,4 @@ import Handler.ExamOffice.Exams as Handler.ExamOffice
|
|||||||
import Handler.ExamOffice.Fields as Handler.ExamOffice
|
import Handler.ExamOffice.Fields as Handler.ExamOffice
|
||||||
import Handler.ExamOffice.Users as Handler.ExamOffice
|
import Handler.ExamOffice.Users as Handler.ExamOffice
|
||||||
import Handler.ExamOffice.Exam as Handler.ExamOffice
|
import Handler.ExamOffice.Exam as Handler.ExamOffice
|
||||||
|
import Handler.ExamOffice.ExternalExam as Handler.ExamOffice
|
||||||
|
|||||||
10
src/Handler/ExamOffice/ExternalExam.hs
Normal file
10
src/Handler/ExamOffice/ExternalExam.hs
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
module Handler.ExamOffice.ExternalExam
|
||||||
|
( getEEGradesR, postEEGradesR
|
||||||
|
) where
|
||||||
|
|
||||||
|
import Import
|
||||||
|
|
||||||
|
|
||||||
|
getEEGradesR, postEEGradesR :: TermId -> SchoolId -> CourseName -> ExamName -> Handler Html
|
||||||
|
getEEGradesR = postEEGradesR
|
||||||
|
postEEGradesR = error "Not implemented"
|
||||||
9
src/Handler/ExternalExam.hs
Normal file
9
src/Handler/ExternalExam.hs
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
module Handler.ExternalExam
|
||||||
|
( module Handler.ExternalExam
|
||||||
|
) where
|
||||||
|
|
||||||
|
import Handler.ExternalExam.List as Handler.ExternalExam
|
||||||
|
import Handler.ExternalExam.New as Handler.ExternalExam
|
||||||
|
import Handler.ExternalExam.Show as Handler.ExternalExam
|
||||||
|
import Handler.ExternalExam.Edit as Handler.ExternalExam
|
||||||
|
import Handler.ExternalExam.Users as Handler.ExternalExam
|
||||||
10
src/Handler/ExternalExam/Edit.hs
Normal file
10
src/Handler/ExternalExam/Edit.hs
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
module Handler.ExternalExam.Edit
|
||||||
|
( getEEEditR, postEEEditR
|
||||||
|
) where
|
||||||
|
|
||||||
|
import Import
|
||||||
|
|
||||||
|
|
||||||
|
getEEEditR, postEEEditR :: TermId -> SchoolId -> CourseName -> ExamName -> Handler Html
|
||||||
|
getEEEditR = postEEEditR
|
||||||
|
postEEEditR = error "Not implemented"
|
||||||
9
src/Handler/ExternalExam/List.hs
Normal file
9
src/Handler/ExternalExam/List.hs
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
module Handler.ExternalExam.List
|
||||||
|
( getEExamListR
|
||||||
|
) where
|
||||||
|
|
||||||
|
import Import
|
||||||
|
|
||||||
|
|
||||||
|
getEExamListR :: Handler Html
|
||||||
|
getEExamListR = error "Not implemented"
|
||||||
10
src/Handler/ExternalExam/New.hs
Normal file
10
src/Handler/ExternalExam/New.hs
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
module Handler.ExternalExam.New
|
||||||
|
( getEExamNewR, postEExamNewR
|
||||||
|
) where
|
||||||
|
|
||||||
|
import Import
|
||||||
|
|
||||||
|
|
||||||
|
getEExamNewR, postEExamNewR :: Handler Html
|
||||||
|
getEExamNewR = postEExamNewR
|
||||||
|
postEExamNewR = error "Not implemented"
|
||||||
9
src/Handler/ExternalExam/Show.hs
Normal file
9
src/Handler/ExternalExam/Show.hs
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
module Handler.ExternalExam.Show
|
||||||
|
( getEEShowR
|
||||||
|
) where
|
||||||
|
|
||||||
|
import Import
|
||||||
|
|
||||||
|
|
||||||
|
getEEShowR :: TermId -> SchoolId -> CourseName -> ExamName -> Handler Html
|
||||||
|
getEEShowR = error "Not implemented"
|
||||||
10
src/Handler/ExternalExam/Users.hs
Normal file
10
src/Handler/ExternalExam/Users.hs
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
module Handler.ExternalExam.Users
|
||||||
|
( getEEUsersR, postEEUsersR
|
||||||
|
) where
|
||||||
|
|
||||||
|
import Import
|
||||||
|
|
||||||
|
|
||||||
|
getEEUsersR, postEEUsersR :: TermId -> SchoolId -> CourseName -> ExamName -> Handler Html
|
||||||
|
getEEUsersR = postEEUsersR
|
||||||
|
postEEUsersR = error "Not implemented"
|
||||||
39
src/Handler/Utils/ExamOffice/ExternalExam.hs
Normal file
39
src/Handler/Utils/ExamOffice/ExternalExam.hs
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
module Handler.Utils.ExamOffice.ExternalExam
|
||||||
|
( examOfficeExternalExamResultAuth
|
||||||
|
) where
|
||||||
|
|
||||||
|
import Import.NoFoundation
|
||||||
|
|
||||||
|
import qualified Database.Esqueleto as E
|
||||||
|
|
||||||
|
|
||||||
|
examOfficeExternalExamResultAuth :: E.SqlExpr (E.Value UserId) -- ^ office
|
||||||
|
-> E.SqlExpr (Entity ExternalExamResult)
|
||||||
|
-> E.SqlExpr (E.Value Bool)
|
||||||
|
examOfficeExternalExamResultAuth authId eexamResult = authByUser E.||. authByField E.||. authBySchool E.||. authByExtraSchool
|
||||||
|
where
|
||||||
|
authByField = E.exists . E.from $ \(examOfficeField `E.InnerJoin` studyFeatures) -> do
|
||||||
|
E.on $ studyFeatures E.^. StudyFeaturesField E.==. examOfficeField E.^. ExamOfficeFieldField
|
||||||
|
E.where_ $ studyFeatures E.^. StudyFeaturesUser E.==. eexamResult E.^. ExternalExamResultUser
|
||||||
|
E.&&. examOfficeField E.^. ExamOfficeFieldOffice E.==. authId
|
||||||
|
E.&&. examOfficeField E.^. ExamOfficeFieldField E.==. studyFeatures E.^. StudyFeaturesField
|
||||||
|
E.where_ $ examOfficeField E.^. ExamOfficeFieldForced
|
||||||
|
E.||. E.exists (E.from $ \userFunction ->
|
||||||
|
E.where_ $ userFunction E.^. UserFunctionUser E.==. authId
|
||||||
|
E.&&. userFunction E.^. UserFunctionFunction E.==. E.val SchoolExamOffice
|
||||||
|
)
|
||||||
|
|
||||||
|
authByUser = E.exists . E.from $ \examOfficeUser ->
|
||||||
|
E.where_ $ examOfficeUser E.^. ExamOfficeUserOffice E.==. authId
|
||||||
|
E.&&. examOfficeUser E.^. ExamOfficeUserUser E.==. eexamResult E.^. ExternalExamResultUser
|
||||||
|
|
||||||
|
authBySchool = E.exists . E.from $ \(userFunction `E.InnerJoin` eexam) -> do
|
||||||
|
E.on $ userFunction E.^. UserFunctionFunction E.==. E.val SchoolExamOffice
|
||||||
|
E.&&. userFunction E.^. UserFunctionSchool E.==. eexam E.^. ExternalExamSchool
|
||||||
|
E.where_ $ eexam E.^. ExternalExamId E.==. eexamResult E.^. ExternalExamResultExam
|
||||||
|
E.where_ $ userFunction E.^. UserFunctionUser E.==. authId
|
||||||
|
authByExtraSchool = E.exists . E.from $ \(userFunction `E.InnerJoin` eexamSchool) -> do
|
||||||
|
E.on $ userFunction E.^. UserFunctionFunction E.==. E.val SchoolExamOffice
|
||||||
|
E.&&. userFunction E.^. UserFunctionSchool E.==. eexamSchool E.^. ExternalExamOfficeSchoolSchool
|
||||||
|
E.where_ $ eexamSchool E.^. ExternalExamOfficeSchoolExam E.==. eexamResult E.^. ExternalExamResultExam
|
||||||
|
E.where_ $ userFunction E.^. UserFunctionUser E.==. authId
|
||||||
@ -1,7 +1,10 @@
|
|||||||
$newline never
|
$newline never
|
||||||
<div .breadcrumbs__container>
|
<div .breadcrumbs__container>
|
||||||
<ul .breadcrumbs__list.list--inline>
|
<ul .breadcrumbs__list.list--inline>
|
||||||
$forall bc <- parents
|
$forall (bcRoute, bcTitle, hasAccess) <- parents
|
||||||
<li .breadcrumbs__item>
|
<li .breadcrumbs__item>
|
||||||
<a .breadcrumbs__link href="@{fst bc}">#{snd bc}
|
$if hasAccess
|
||||||
|
<a .breadcrumbs__link href="@{bcRoute}">#{bcTitle}
|
||||||
|
$else
|
||||||
|
<span .breadcrumbs__link>#{bcTitle}
|
||||||
<li .breadcrumbs__last-item>#{title}
|
<li .breadcrumbs__last-item>#{title}
|
||||||
|
|||||||
63
templates/widgets/breadcrumbs/breadcrumbs.lucius
Normal file
63
templates/widgets/breadcrumbs/breadcrumbs.lucius
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
.breadcrumbs__container {
|
||||||
|
position: relative;
|
||||||
|
color: var(--color-lightwhite);
|
||||||
|
padding: 4px 13px;
|
||||||
|
background-color: var(--color-dark);
|
||||||
|
line-height: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width: 426px) {
|
||||||
|
.breadcrumbs__container {
|
||||||
|
padding: 7px 20px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width: 769px) {
|
||||||
|
.breadcrumbs__container {
|
||||||
|
padding: 7px 40px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
a.breadcrumbs__link {
|
||||||
|
color: var(--color-lightwhite);
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
color: var(--color-white);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.breadcrumbs__item {
|
||||||
|
padding-right: 14px;
|
||||||
|
position: relative;
|
||||||
|
line-height: 28px;
|
||||||
|
opacity: 0.8;
|
||||||
|
z-index: 1;
|
||||||
|
margin-right: 10px;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
&::after {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
top: 11px;
|
||||||
|
right: 0;
|
||||||
|
width: 7px;
|
||||||
|
height: 7px;
|
||||||
|
border-style: solid;
|
||||||
|
border-width: 0;
|
||||||
|
border-bottom-width: 1px;
|
||||||
|
border-right-width: 1px;
|
||||||
|
border-color: var(--color-white);
|
||||||
|
transform: rotate(-45deg);
|
||||||
|
z-index: 10;
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.breadcrumbs__last-item {
|
||||||
|
line-height: 28px;
|
||||||
|
vertical-align: bottom;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user