diff --git a/messages/uniworx/de-de-formal.msg b/messages/uniworx/de-de-formal.msg index 07095c592..1a687b865 100644 --- a/messages/uniworx/de-de-formal.msg +++ b/messages/uniworx/de-de-formal.msg @@ -457,6 +457,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. 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. +UnauthorizedSystemExamOffice: Sie sind nicht mit systemweiter Prüfungsverwaltung beauftragt. UnauthorizedExternalExamExamOffice: Es existieren keine Prüfungsergebnisse für Nutzer, für die Sie mit der Prüfungsverwaltung beauftragt sind. UnauthorizedEvaluation: Sie sind nicht mit der Kursumfragenverwaltung beauftragt. UnauthorizedAllocationAdmin: Sie sind nicht mit der Administration von Zentralanmeldungen beauftragt. @@ -765,6 +766,9 @@ CorrectorsFor n@Int: #{pluralDE n "Korrektor" "Korrektoren"} UserListTitle: Komprehensive Benutzerliste AccessRightsSaved: Berechtigungen erfolgreich verändert AccessRightsNotChanged: Berechtigungen wurden nicht verändert +UserSystemFunctions: Systemweite Rollen +UserSystemFunctionsSaved: Systemweite Rollen gespeichert +UserSystemFunctionsNotChanged: Es wurden keine systemweiten Rollen angepasst LecturersForN n@Int: #{pluralDE n "Dozent" "Dozenten"} @@ -1014,6 +1018,10 @@ MailUserRightsIntro name@Text email@UserEmail: #{name} <#{email}> hat folgende U MailNoLecturerRights: Sie haben derzeit keine Dozenten-Rechte. MailLecturerRights n@Int: Als Dozent dürfen Sie Veranstaltungen innerhalb #{pluralDE n "Ihres Instituts" "Ihrer Institute"} anlegen. +MailSubjectUserSystemFunctionsUpdate name@Text: Berechtigungen für #{name} aktualisiert +MailUserSystemFunctionsIntro name@Text email@UserEmail: #{name} <#{email}> hat folgende Uni2work nicht-institutsbezogene Berechtigungen: +MailUserSystemFunctionsNoFunctions: Keine + MailSubjectUserAuthModeUpdate: Ihr Uni2work-Login UserAuthModePWHashChangedToLDAP: Sie können sich nun mit Ihrer Campus-Kennung in Uni2work einloggen UserAuthModeLDAPChangedToPWHash: Sie können sich nun mit einer Uni2work-internen Kennung in Uni2work einloggen @@ -1448,6 +1456,7 @@ AuthPredsActiveChanged: Authorisierungseinstellungen für aktuelle Sitzung gespe AuthTagFree: Seite ist universell zugänglich AuthTagAdmin: Nutzer ist Administrator AuthTagExamOffice: Nutzer ist mit Prüfungsverwaltung beauftragt +AuthTagSystemExamOffice: Nutzer ist mit systemweiter Prüfungsverwaltung beauftragt AuthTagEvaluation: Nutzer ist mit Kursumfragenverwaltung beauftragt AuthTagAllocationAdmin: Nutzer ist mit der Administration von Zentralanmeldungen beauftragt AuthTagToken: Nutzer präsentiert Authorisierungs-Token @@ -2750,3 +2759,6 @@ SheetPersonalisedFilesUsersList: Liste von Teilnehmern mit personalisierten Übu AdminCrontabNotGenerated: (Noch) keine Crontab generiert CronMatchAsap: ASAP CronMatchNone: Nie + +SystemExamOffice: Prüfungsverwaltung +SystemFaculty: Fakultätsmitglied \ No newline at end of file diff --git a/messages/uniworx/en-eu.msg b/messages/uniworx/en-eu.msg index 1c236b868..a33b05a8f 100644 --- a/messages/uniworx/en-eu.msg +++ b/messages/uniworx/en-eu.msg @@ -457,6 +457,7 @@ UnauthorizedExamOffice: You are not part of an exam office. UnauthorizedEvaluation: You are not charged with course evaluation. UnauthorizedAllocationAdmin: You are not charged with the administration of central allocations. UnauthorizedExamExamOffice: You are not part of the appropriate exam office for any of the participants of this exam. +UnauthorizedSystemExamOffice: You are not charged with system wide exam administration 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. @@ -762,6 +763,9 @@ CorrectorsFor n: #{pluralEN n "Corrector" "Correctors"} UserListTitle: Comprehensive list of users AccessRightsSaved: Successfully updated permissions AccessRightsNotChanged: Permissions left unchanged +UserSystemFunctions: System wide roles +UserSystemFunctionsSaved: Successfully saved system wide roles +UserSystemFunctionsNotChanged: No system wide roles were changed LecturersForN n: #{pluralEN n "Lecturer" "Lecturers"} @@ -1014,6 +1018,10 @@ MailUserRightsIntro name email: #{name} <#{email}> now has the following permiss MailNoLecturerRights: You don't currently have lecturer permissions for any department. MailLecturerRights n: As a lecturer you may create new courses within your #{pluralEN n "department" "departments"}. +MailSubjectUserSystemFunctionsUpdate name: Permissions for #{name} changed +MailUserSystemFunctionsIntro name email: #{name} <#{email}> now has the following, not school restricted, permissions: +MailUserSystemFunctionsNoFunctions: None + MailSubjectUserAuthModeUpdate: Your Uni2work login UserAuthModePWHashChangedToLDAP: You can now log in to Uni2work using your Campus-account UserAuthModeLDAPChangedToPWHash: You can now log in to Uni2work using your Uni2work-internal account @@ -1448,6 +1456,7 @@ AuthPredsActiveChanged: Authorisation settings saved for the current session AuthTagFree: Page is freely accessable AuthTagAdmin: User is administrator AuthTagExamOffice: User is part of an exam office +AuthTagSystemExamOffice: User is charged with system wide exam administration AuthTagEvaluation: User is charged with course evaluation AuthTagAllocationAdmin: User is charged with administration of central allocations AuthTagToken: User is presenting an authorisation-token @@ -2751,3 +2760,6 @@ SheetPersonalisedFilesUsersList: List of course participants who have personalis AdminCrontabNotGenerated: Crontab not (yet) generated CronMatchAsap: ASAP CronMatchNone: Never + +SystemExamOffice: Exam office +SystemFaculty: Faculty member diff --git a/models/users.model b/models/users.model index 740de8186..2d18206b3 100644 --- a/models/users.model +++ b/models/users.model @@ -42,6 +42,12 @@ UserFunction -- Administratively assigned functions (lecturer, admin, evaluation school SchoolId function SchoolFunction UniqueUserFunction user school function +UserSystemFunction + user UserId + function SystemFunction + manual Bool + isOptOut Bool + UniqueUserSystemFunction user function UserExamOffice user UserId field StudyTermsId diff --git a/routes b/routes index 1bb1c3f9a..810aeb824 100644 --- a/routes +++ b/routes @@ -79,10 +79,10 @@ /user/storage-key StorageKeyR POST !free /exam-office ExamOfficeR !exam-office: - / EOExamsR GET + / EOExamsR GET !system-exam-office /fields EOFieldsR GET POST - /users EOUsersR GET POST - /users/invite EOUsersInviteR GET POST + /users EOUsersR GET POST !system-exam-office + /users/invite EOUsersInviteR GET POST !system-exam-office /external-exam EExamListR GET !lecturer !¬empty /external-exam/new EExamNewR GET POST !lecturer diff --git a/src/Auth/LDAP.hs b/src/Auth/LDAP.hs index 9b57c8904..57270e2c6 100644 --- a/src/Auth/LDAP.hs +++ b/src/Auth/LDAP.hs @@ -10,6 +10,7 @@ module Auth.LDAP , ldapUserMatriculation, ldapUserFirstName, ldapUserSurname , ldapUserTitle, ldapUserStudyFeatures, ldapUserFieldName , ldapUserSchoolAssociation, ldapUserSubTermsSemester, ldapSex + , ldapAffiliation ) where import Import.NoFoundation @@ -68,7 +69,7 @@ userSearchSettings LdapConf{..} = mconcat , Ldap.derefAliases Ldap.DerefAlways ] -ldapUserPrincipalName, ldapUserDisplayName, ldapUserMatriculation, ldapUserFirstName, ldapUserSurname, ldapUserTitle, ldapUserStudyFeatures, ldapUserFieldName, ldapUserSchoolAssociation, ldapSex, ldapUserSubTermsSemester :: Ldap.Attr +ldapUserPrincipalName, ldapUserDisplayName, ldapUserMatriculation, ldapUserFirstName, ldapUserSurname, ldapUserTitle, ldapUserStudyFeatures, ldapUserFieldName, ldapUserSchoolAssociation, ldapSex, ldapUserSubTermsSemester, ldapAffiliation :: Ldap.Attr ldapUserPrincipalName = Ldap.Attr "userPrincipalName" ldapUserDisplayName = Ldap.Attr "displayName" ldapUserMatriculation = Ldap.Attr "LMU-Stud-Matrikelnummer" @@ -80,6 +81,7 @@ ldapUserFieldName = Ldap.Attr "LMU-Stg-Fach" ldapUserSchoolAssociation = Ldap.Attr "LMU-IFI-eduPersonOrgUnitDNString" ldapSex = Ldap.Attr "schacGender" ldapUserSubTermsSemester = Ldap.Attr "LMU-Stg-FachundFS" +ldapAffiliation = Ldap.Attr "eduPersonAffiliation" ldapUserEmail :: NonEmpty Ldap.Attr ldapUserEmail = Ldap.Attr "mail" :| diff --git a/src/Foundation/Authorization.hs b/src/Foundation/Authorization.hs index 991224b2f..0997791f4 100644 --- a/src/Foundation/Authorization.hs +++ b/src/Foundation/Authorization.hs @@ -324,6 +324,11 @@ tagAccessPredicate AuthAdmin = APDB $ \mAuthId route _ -> case route of adrights <- lift $ selectFirst [UserFunctionUser ==. authId, UserFunctionFunction ==. SchoolAdmin] [] guardMExceptT (isJust adrights) (unauthorizedI MsgUnauthorizedSiteAdmin) return Authorized +tagAccessPredicate AuthSystemExamOffice = APDB $ \mAuthId _ _ -> $cachedHereBinary mAuthId . exceptT return return $ do + authId <- maybeExceptT AuthenticationRequired $ return mAuthId + isExamOffice <- lift $ exists [UserSystemFunctionUser ==. authId, UserSystemFunctionFunction ==. SystemExamOffice, UserSystemFunctionIsOptOut ==. False] + guardMExceptT isExamOffice $ unauthorizedI MsgUnauthorizedSystemExamOffice + return Authorized tagAccessPredicate AuthExamOffice = APDB $ \mAuthId route _ -> case route of CExamR tid ssh csh examn _ -> $cachedHereBinary (mAuthId, tid, ssh, csh, examn) . exceptT return return $ do authId <- maybeExceptT AuthenticationRequired $ return mAuthId diff --git a/src/Foundation/I18n.hs b/src/Foundation/I18n.hs index aa514a72d..71543f2d9 100644 --- a/src/Foundation/I18n.hs +++ b/src/Foundation/I18n.hs @@ -219,6 +219,7 @@ embedRenderMessage ''UniWorX ''UploadModeDescr id embedRenderMessage ''UniWorX ''SecretJSONFieldException id embedRenderMessage ''UniWorX ''AFormMessage $ concat . drop 2 . splitCamel embedRenderMessage ''UniWorX ''SchoolFunction id +embedRenderMessage ''UniWorX ''SystemFunction id embedRenderMessage ''UniWorX ''CsvPreset id embedRenderMessage ''UniWorX ''Quoting ("Csv" <>) embedRenderMessage ''UniWorX ''FavouriteReason id diff --git a/src/Foundation/Yesod/Auth.hs b/src/Foundation/Yesod/Auth.hs index 8be3e80b9..12fb36028 100644 --- a/src/Foundation/Yesod/Auth.hs +++ b/src/Foundation/Yesod/Auth.hs @@ -14,6 +14,7 @@ import Foundation.I18n import Handler.Utils.Profile import Handler.Utils.StudyFeatures import Handler.Utils.SchoolLdap +import Handler.Utils.LdapSystemFunctions import Yesod.Auth.Message import Auth.LDAP @@ -22,6 +23,7 @@ import qualified Data.CaseInsensitive as CI import qualified Control.Monad.Catch as C (Handler(..)) import qualified Data.List.NonEmpty as NonEmpty import qualified Ldap.Client as Ldap +import qualified Data.Text as Text import qualified Data.Text.Encoding as Text import qualified Data.ByteString as ByteString import qualified Data.Set as Set @@ -425,6 +427,19 @@ upsertCampusUser plugin ldapData = do forM_ ss $ void . insertUnique . SchoolLdap Nothing + let + userSystemFunctions = determineSystemFunctions . Set.fromList $ map CI.mk userSystemFunctions' + userSystemFunctions' = do + (k, v) <- ldapData + guard $ k == ldapAffiliation + v' <- v + Right str <- return $ Text.decodeUtf8' v' + assertM' (not . Text.null) $ Text.strip str + + iforM_ userSystemFunctions $ \func preset -> if + | preset -> void $ upsert (UserSystemFunction userId func False False) [] + | otherwise -> deleteWhere [UserSystemFunctionUser ==. userId, UserSystemFunctionFunction ==. func, UserSystemFunctionIsOptOut ==. False, UserSystemFunctionManual ==. False] + return user where insertMaybe key val = get key >>= maybe (insert_ val) (\_ -> return ()) diff --git a/src/Handler/Users.hs b/src/Handler/Users.hs index 88d0340fd..b5e8313e9 100644 --- a/src/Handler/Users.hs +++ b/src/Handler/Users.hs @@ -101,6 +101,9 @@ postUsersR = do $forall (E.Value sh) <- schools