diff --git a/messages/uniworx/categories/school/de-de-formal.msg b/messages/uniworx/categories/school/de-de-formal.msg index 28cf19c0e..d4feac656 100644 --- a/messages/uniworx/categories/school/de-de-formal.msg +++ b/messages/uniworx/categories/school/de-de-formal.msg @@ -4,6 +4,8 @@ SchoolName !ident-ok: Name SchoolLdapOrganisations: Assoziierte LDAP-Fragmente SchoolLdapOrganisationsTip: Beim Login via LDAP werden dem Nutzer/der Nutzerin alle Institute zugeordnet deren assoziierte LDAP-Fragmente im Eintrag des Nutzer/der Nutzerin gefunden werden SchoolLdapOrganisationMissing: LDAP-Fragment wird benötigt + +SchoolExamSection: Prüfungen SchoolExamMinimumRegisterBeforeStart: Minimale Tage zwischen Anmeldebeginn und Termin für Prüfungen SchoolExamMinimumRegisterBeforeStartTip: Wenn angegeben werden Dozierende gezwungen Anmeldezeitraum und Prüfungstermin stets zusammen einzustellen. SchoolExamMinimumRegisterDuration: Minimale Anmeldedauer für Prüfungen @@ -12,6 +14,18 @@ SchoolExamRequireModeForRegistration: Prüfungsmodus erforderlich für Anmeldung SchoolExamRequireModeForRegistrationTip: Sollen Dozierende gezwungen werden Prüfungsmodus und Anmeldefrist stets zusammen einzustellen? SchoolExamDiscouragedModes: Prüfungsmodi mit Warnung ExamCloseMode: Prüfungs-Abschluss + +SchoolAuthorshipStatementSection: Eigenständigkeitserklärungen +SchoolAuthorshipStatementModeNone: Keine Eigenständigkeitserklärung erlauben +SchoolAuthorshipStatementModeOptional: Eigenständigkeitserklärung optional einforderbar +SchoolAuthorshipStatementModeRequired: Eigenständigkeitserklärung immer erforderlich +SchoolSheetAuthorshipStatementMode: Modus für nicht-prüfungsrelevante Übungsblattabgaben +SchoolSheetAuthorshipStatementExamMode: Modus für prüfungsrelevante Übungsblattabgaben +SchoolSheetAuthorshipStatementText: Eigenständigkeitserklärung +SchoolSheetAuthorshipStatementTextTip: Dieser Text dient als Standard-Eigenständigkeitserklärung beim Anlegen eines neuen Übungsblattes innerhalb eines Kurses dieses Instituts. Wenn Anpassungen erlaubt sind, kann diese Erklärung pro Übungsblatt durch einen Dozierenden überschrieben werden. +SchoolSheetAuthorshipStatementAllowOther: Anpassungen erlauben? +SchoolSheetAuthorshipStatementAllowOtherTip: Soll es Dozierenden erlaubt sein, pro Übungsblatt eine abweichende Eigenständigkeitserklärung anzugeben? + SchoolUpdated ssh@SchoolId: #{ssh} erfolgreich angepasst SchoolTitle ssh@SchoolId: Institut „#{ssh}“ TitleSchoolNew: Neues Institut anlegen diff --git a/messages/uniworx/categories/school/en-eu.msg b/messages/uniworx/categories/school/en-eu.msg index c15e02e7a..aa7d295fc 100644 --- a/messages/uniworx/categories/school/en-eu.msg +++ b/messages/uniworx/categories/school/en-eu.msg @@ -4,6 +4,8 @@ SchoolName: Name SchoolLdapOrganisations: Associated LDAP fragments SchoolLdapOrganisationsTip: When logging in users are associated with any departments whose associated LDAP fragments are found in the users LDAP entry SchoolLdapOrganisationMissing: LDAP-fragment is required + +SchoolExamSection: Exams SchoolExamMinimumRegisterBeforeStart: Minimum number of days between start of registration period and start of exams SchoolExamMinimumRegisterBeforeStartTip: If specified course administrators will be forced to specify the start of the registration period and the start of the exam at the same time. SchoolExamMinimumRegisterDuration: Minimum duration of registration period for exams @@ -12,6 +14,18 @@ SchoolExamRequireModeForRegistration: Exam design required for registration SchoolExamRequireModeForRegistrationTip: Should course administrators be forced to fully specify their exam design when setting a registration period? SchoolExamDiscouragedModes: Exam designs to warn against ExamCloseMode: Exam closure + +SchoolAuthorshipStatementSection: Statements of Authorship +SchoolAuthorshipStatementModeNone: No Statement of Authorship allowed +SchoolAuthorshipStatementModeOptional: Statement of Authorship optionally activatable +SchoolAuthorshipStatementModeRequired: Statement of Authorship always required +SchoolSheetAuthorshipStatementMode: Mode for exam-unrelated exercise sheets +SchoolSheetAuthorshipStatementExamMode: Mode for exam-related sheets +SchoolSheetAuthorshipStatementText: Statement of Authorship +SchoolSheetAuthorshipStatementTextTip: This text serves as default Statement of Authorship upon creating a new exercise sheet in a course of this school. This statement may be overriden by a course administrator per exercise sheet if adaptations are allowed. +SchoolSheetAuthorshipStatementAllowOther: Allow adaptations? +SchoolSheetAuthorshipStatementAllowOtherTip: Should course administrators be allowed to specify an alternative Statement of Authorship? + SchoolUpdated ssh: Successfully edited #{ssh} SchoolTitle ssh: Department „#{ssh}“ TitleSchoolNew: Create new department diff --git a/models/schools.model b/models/schools.model index 33975b7a3..b686b7964 100644 --- a/models/schools.model +++ b/models/schools.model @@ -8,6 +8,10 @@ School json examRequireModeForRegistration Bool default=false examDiscouragedModes ExamModeDNF examCloseMode ExamCloseMode default='separate' + sheetAuthorshipStatementMode SchoolAuthorshipStatementMode default='optional' + sheetAuthorshipStatementExamMode SchoolAuthorshipStatementMode default='optional' + sheetAuthorshipStatementText Text Maybe + sheetAuthorshipStatementAllowOther Bool default=true UniqueSchool name UniqueSchoolShorthand shorthand -- required for Normalisation of CI Text Primary shorthand -- newtype Key School = SchoolKey { unSchoolKey :: SchoolShorthand } diff --git a/src/Foundation/I18n.hs b/src/Foundation/I18n.hs index b720355c6..17f4d418b 100644 --- a/src/Foundation/I18n.hs +++ b/src/Foundation/I18n.hs @@ -404,6 +404,15 @@ instance RenderMessage UniWorX ExamCloseMode where mr :: RenderMessage UniWorX msg => msg -> Text mr = renderMessage foundation ls +instance RenderMessage UniWorX SchoolAuthorshipStatementMode where + renderMessage foundation ls = \case + SchoolAuthorshipStatementModeNone -> mr MsgSchoolAuthorshipStatementModeNone + SchoolAuthorshipStatementModeOptional -> mr MsgSchoolAuthorshipStatementModeOptional + SchoolAuthorshipStatementModeRequired -> mr MsgSchoolAuthorshipStatementModeRequired + where + mr :: RenderMessage UniWorX msg => msg -> Text + mr = renderMessage foundation ls + -- ToMessage instances for converting raw numbers to Text (no internationalization) -- FIXME: Use RenderMessage always diff --git a/src/Handler/School.hs b/src/Handler/School.hs index c6373ae23..38cc9bf18 100644 --- a/src/Handler/School.hs +++ b/src/Handler/School.hs @@ -68,6 +68,10 @@ data SchoolForm = SchoolForm , sfExamRequireModeForRegistration :: Bool , sfExamDiscouragedModes :: ExamModeDNF , sfExamCloseMode :: ExamCloseMode + , sfSheetAuthorshipStatementMode :: SchoolAuthorshipStatementMode + , sfSheetAuthorshipStatementExamMode :: SchoolAuthorshipStatementMode + , sfSheetAuthorshipStatementText :: Maybe Text + , sfSheetAuthorshipStatementAllowOther :: Bool } mkSchoolForm :: Maybe SchoolId -> Maybe SchoolForm -> Form SchoolForm @@ -75,11 +79,17 @@ mkSchoolForm mSsh template = renderAForm FormStandard $ SchoolForm <$> maybe (\f fs -> areq f fs (sfShorthand <$> template)) (\ssh f fs -> aforced f fs (unSchoolKey ssh)) mSsh (textField & cfStrip & cfCI) (fslI MsgSchoolShort) <*> areq (textField & cfStrip & cfCI) (fslI MsgSchoolName) (sfName <$> template) <*> (Set.fromList . mapMaybe (fmap CI.mk . assertM' (not . Text.null) . Text.strip . CI.original) <$> massInputListA (ciField & addDatalist ldapOrgs) (const "") MsgSchoolLdapOrganisationMissing (const Nothing) ("ldap-organisations" :: Text) (fslI MsgSchoolLdapOrganisations & setTooltip MsgSchoolLdapOrganisationsTip) False (Set.toList . sfOrgUnits <$> template)) + <* aformSection MsgSchoolExamSection <*> aopt daysField (fslI MsgSchoolExamMinimumRegisterBeforeStart & setTooltip MsgSchoolExamMinimumRegisterBeforeStartTip) (sfExamMinimumRegisterBeforeStart <$> template) <*> aopt daysField (fslI MsgSchoolExamMinimumRegisterDuration & setTooltip MsgSchoolExamMinimumRegisterDurationTip) (sfExamMinimumRegisterDuration <$> template) <*> apopt checkBoxField (fslI MsgSchoolExamRequireModeForRegistration & setTooltip MsgSchoolExamRequireModeForRegistration) (sfExamRequireModeForRegistration <$> template) <*> areq pathPieceField (fslI MsgSchoolExamDiscouragedModes) (sfExamDiscouragedModes <$> template <|> pure (ExamModeDNF predDNFFalse)) <*> apopt (selectField optionsFinite) (fslI MsgExamCloseMode) (sfExamCloseMode <$> template <|> pure ExamCloseSeparate) + <* aformSection MsgSchoolAuthorshipStatementSection + <*> apopt (selectField optionsFinite) (fslI MsgSchoolSheetAuthorshipStatementMode) (sfSheetAuthorshipStatementMode <$> template <|> pure SchoolAuthorshipStatementModeOptional) + <*> apopt (selectField optionsFinite) (fslI MsgSchoolSheetAuthorshipStatementExamMode) (sfSheetAuthorshipStatementExamMode <$> template <|> pure SchoolAuthorshipStatementModeOptional) + <*> aopt (textField & cfStrip) (fslI MsgSchoolSheetAuthorshipStatementText & setTooltip MsgSchoolSheetAuthorshipStatementTextTip) (sfSheetAuthorshipStatementText <$> template) -- TODO: use htmlField + <*> apopt checkBoxField (fslI MsgSchoolSheetAuthorshipStatementAllowOther & setTooltip MsgSchoolSheetAuthorshipStatementAllowOtherTip) (sfSheetAuthorshipStatementAllowOther <$> template <|> pure True) where ldapOrgs :: HandlerFor UniWorX (OptionList (CI Text)) ldapOrgs = fmap (mkOptionList . map (\t -> Option (CI.original t) t (CI.original t)) . Set.toAscList) . runDB $ @@ -98,6 +108,10 @@ schoolToForm ssh = do , sfExamRequireModeForRegistration = schoolExamRequireModeForRegistration , sfExamDiscouragedModes = schoolExamDiscouragedModes , sfExamCloseMode = schoolExamCloseMode + , sfSheetAuthorshipStatementMode = schoolSheetAuthorshipStatementMode + , sfSheetAuthorshipStatementExamMode = schoolSheetAuthorshipStatementExamMode + , sfSheetAuthorshipStatementText = schoolSheetAuthorshipStatementText + , sfSheetAuthorshipStatementAllowOther = schoolSheetAuthorshipStatementAllowOther } @@ -108,6 +122,8 @@ postSchoolEditR ssh = do ((sfResult, sfView), sfEnctype) <- runFormPost sForm + -- TODO: validate Form: when AuthorshipStatement required, the statement text must be `Just t` with `t` non-empty + formResult sfResult $ \SchoolForm{..} -> do runDB $ do update ssh @@ -117,6 +133,10 @@ postSchoolEditR ssh = do , SchoolExamRequireModeForRegistration =. sfExamRequireModeForRegistration , SchoolExamDiscouragedModes =. sfExamDiscouragedModes , SchoolExamCloseMode =. sfExamCloseMode + , SchoolSheetAuthorshipStatementMode =. sfSheetAuthorshipStatementMode + , SchoolSheetAuthorshipStatementExamMode =. sfSheetAuthorshipStatementExamMode + , SchoolSheetAuthorshipStatementText =. sfSheetAuthorshipStatementText + , SchoolSheetAuthorshipStatementAllowOther =. sfSheetAuthorshipStatementAllowOther ] forM_ sfOrgUnits $ \schoolLdapOrgUnit -> void $ upsert SchoolLdap @@ -159,6 +179,10 @@ postSchoolNewR = do , schoolExamRequireModeForRegistration = sfExamRequireModeForRegistration , schoolExamDiscouragedModes = sfExamDiscouragedModes , schoolExamCloseMode = sfExamCloseMode + , schoolSheetAuthorshipStatementMode = sfSheetAuthorshipStatementMode + , schoolSheetAuthorshipStatementExamMode = sfSheetAuthorshipStatementExamMode + , schoolSheetAuthorshipStatementText = sfSheetAuthorshipStatementText + , schoolSheetAuthorshipStatementAllowOther = sfSheetAuthorshipStatementAllowOther } when didInsert $ do insert_ UserFunction diff --git a/src/Model/Types/School.hs b/src/Model/Types/School.hs index 0b9f65634..bb739f563 100644 --- a/src/Model/Types/School.hs +++ b/src/Model/Types/School.hs @@ -17,3 +17,16 @@ pathPieceJSON ''SchoolFunction pathPieceJSONKey ''SchoolFunction derivePersistFieldPathPiece ''SchoolFunction pathPieceBinary ''SchoolFunction + +data SchoolAuthorshipStatementMode + = SchoolAuthorshipStatementModeNone + | SchoolAuthorshipStatementModeOptional + | SchoolAuthorshipStatementModeRequired + deriving (Eq, Ord, Enum, Bounded, Read, Show, Generic, Typeable) + deriving anyclass (Universe, Finite, NFData) + +nullaryPathPiece ''SchoolAuthorshipStatementMode $ camelToPathPiece' 4 +pathPieceJSON ''SchoolAuthorshipStatementMode +pathPieceJSONKey ''SchoolAuthorshipStatementMode +derivePersistFieldPathPiece ''SchoolAuthorshipStatementMode +pathPieceBinary ''SchoolAuthorshipStatementMode diff --git a/test/Database/Fill.hs b/test/Database/Fill.hs index b97ed31e3..e3a22a6c4 100644 --- a/test/Database/Fill.hs +++ b/test/Database/Fill.hs @@ -411,8 +411,8 @@ fillDb = do , termLectureEnd } void . insert_ $ TermActive (TermKey term) (toMidnight $ addDays (-60) termStart) (Just . beforeMidnight $ addDays 60 termEnd) Nothing - ifi <- insert' $ School "Institut für Informatik" "IfI" (Just $ 14 * nominalDay) (Just $ 10 * nominalDay) True (ExamModeDNF predDNFFalse) (ExamCloseOnFinished True) - mi <- insert' $ School "Institut für Mathematik" "MI" Nothing Nothing False (ExamModeDNF predDNFFalse) (ExamCloseOnFinished False) + ifi <- insert' $ School "Institut für Informatik" "IfI" (Just $ 14 * nominalDay) (Just $ 10 * nominalDay) True (ExamModeDNF predDNFFalse) (ExamCloseOnFinished True) SchoolAuthorshipStatementModeOptional SchoolAuthorshipStatementModeRequired (Just "Erklärung über die eigenständige Bearbeitung\n\nHiermit erkläre ich, dass ich die vorliegende Abgabe vollständig selbstständig angefertigt habe, bzw. dass bei einer Gruppen-Abgabe nur die bei der Abgabe benannten Personen mitgewirkt haben.\n\nQuellen und Hilfsmittel über den Rahmen der Lehrveranstaltung hinaus sind als solche markiert und angegeben. Direkte Zitate sind als solche kenntlich gemacht.\n\nIch bin mir darüber im Klaren, dass Verstöße durch Plagiate oder Zusammenarbeit mit Dritten zum Ausschluss von der Veranstaltung führen.") False + mi <- insert' $ School "Institut für Mathematik" "MI" Nothing Nothing False (ExamModeDNF predDNFFalse) (ExamCloseOnFinished False) SchoolAuthorshipStatementModeNone SchoolAuthorshipStatementModeOptional Nothing True void . insert' $ UserFunction gkleen ifi SchoolAdmin void . insert' $ UserFunction gkleen mi SchoolAdmin void . insert' $ UserFunction fhamann ifi SchoolAdmin