Merge branch 'i18n' of gitlab.cip.ifi.lmu.de:jost/UniWorX into i18n

This commit is contained in:
Sarah Vaupel 2019-10-23 19:57:25 +02:00
commit 778b69dd26
24 changed files with 360 additions and 123 deletions

View File

@ -1,5 +1,6 @@
CampusIdentPlaceholder: Vorname.Nachname@campus.lmu.de CampusIdentPlaceholder: Vorname.Nachname@campus.lmu.de
CampusIdent: Campus-Kennung CampusIdent: Campus-Kennung
CampusPassword: Passwort CampusPassword: Passwort
CampusPasswordPlaceholder: Passwort
CampusSubmit: Abschicken CampusSubmit: Abschicken
CampusInvalidCredentials: Ungültige Logindaten CampusInvalidCredentials: Ungültige Logindaten

View File

@ -1,2 +1,3 @@
DummyIdent: Nutzer-Kennung DummyIdent: Identifikation
DummyIdentPlaceholder: Identifikation
DummyNoFormData: Keine Formulardaten empfangen DummyNoFormData: Keine Formulardaten empfangen

View File

@ -1,2 +1,4 @@
PWHashIdent: Identifikation PWHashIdent: Identifikation
PWHashIdentPlaceholder: Identifikation
PWHashPassword: Passwort PWHashPassword: Passwort
PWHashPasswordPlaceholder: Passwort

View File

@ -73,9 +73,9 @@ Term: Semester
TermPlaceholder: W/S + vierstellige Jahreszahl TermPlaceholder: W/S + vierstellige Jahreszahl
TermStartDay: Erster Tag TermStartDay: Erster Tag
TermStartDayTooltip: Üblicherweise immer 1.April oder 1.Oktober TermStartDayTooltip: Üblicherweise immer 1. April oder 1. Oktober
TermEndDay: Letzter Tag TermEndDay: Letzter Tag
TermEndDayTooltip: Üblicherweise immer 30.September oder 31.März TermEndDayTooltip: Üblicherweise immer 30. September oder 31. März
TermHolidays: Feiertage TermHolidays: Feiertage
TermHolidayPlaceholder: Feiertag TermHolidayPlaceholder: Feiertag
TermLectureStart: Beginn Vorlesungen TermLectureStart: Beginn Vorlesungen
@ -111,8 +111,8 @@ CourseTutorial: Tutorium
CourseSecretWrong: Falsches Passwort CourseSecretWrong: Falsches Passwort
CourseSecret: Zugangspasswort CourseSecret: Zugangspasswort
CourseEditOk tid@TermId ssh@SchoolId csh@CourseShorthand: Kurs #{tid}-#{ssh}-#{csh} wurde erfolgreich geändert. CourseEditOk tid@TermId ssh@SchoolId csh@CourseShorthand: Kurs #{tid}-#{ssh}-#{csh} wurde erfolgreich geändert.
CourseNewDupShort tid@TermId ssh@SchoolId csh@CourseShorthand: Kurs #{tid}-#{ssh}-#{csh} konnte nicht erstellt werden: Es gibt bereits einen anderen Kurs mit dem Kürzel #{csh} in diesem Semester. CourseNewDupShort tid@TermId ssh@SchoolId csh@CourseShorthand: Kurs #{tid}-#{ssh}-#{csh} konnte nicht erstellt werden: Es gibt bereits einen anderen Kurs mit dem Kürzel #{csh} in diesem Semester und Institut.
CourseEditDupShort tid@TermId ssh@SchoolId csh@CourseShorthand: Kurs #{tid}-#{ssh}-#{csh} konnte nicht geändert werden: Es gibt bereits einen anderen Kurs mit dem Kürzel #{csh} in diesem Semester. CourseEditDupShort tid@TermId ssh@SchoolId csh@CourseShorthand: Kurs #{tid}-#{ssh}-#{csh} konnte nicht geändert werden: Es gibt bereits einen anderen Kurs mit dem Kürzel #{csh} in diesem Semester und Institut.
FFSheetName: Name FFSheetName: Name
TermCourseListHeading tid@TermId: Kursübersicht #{tid} TermCourseListHeading tid@TermId: Kursübersicht #{tid}
TermSchoolCourseListHeading tid@TermId school@SchoolName: Kursübersicht #{tid} für #{school} TermSchoolCourseListHeading tid@TermId school@SchoolName: Kursübersicht #{tid} für #{school}
@ -130,7 +130,7 @@ CourseMembersCountLimited n@Int max@Int: #{n}/#{max}
CourseMembersCountOf n@Int mbNum@IntMaybe: #{n} Kursanmeldungen #{maybeToMessage " von " mbNum " möglichen"} CourseMembersCountOf n@Int mbNum@IntMaybe: #{n} Kursanmeldungen #{maybeToMessage " von " mbNum " möglichen"}
CourseName: Name CourseName: Name
CourseDescription: Beschreibung CourseDescription: Beschreibung
CourseDescriptionTip: Beliebiges HTML-Markup ist gestattet CourseDescriptionTip: Beliebiges Html-Markup ist gestattet
CourseHomepageExternal: Externe Homepage CourseHomepageExternal: Externe Homepage
CourseShorthand: Kürzel CourseShorthand: Kürzel
CourseShorthandUnique: Muss nur innerhalb Institut und Semester eindeutig sein. Wird verbatim in die Url der Kursseite übernommen. CourseShorthandUnique: Muss nur innerhalb Institut und Semester eindeutig sein. Wird verbatim in die Url der Kursseite übernommen.
@ -274,6 +274,8 @@ SheetSubmissionMode: Abgabe-Modus
SheetExercise: Aufgabenstellung SheetExercise: Aufgabenstellung
SheetHint: Hinweis SheetHint: Hinweis
SheetHintFrom: Hinweis ab SheetHintFrom: Hinweis ab
SheetHintFromPlaceholder: Datum, sonst nur für Korrektoren
SheetSolutionFromPlaceholder: Datum, sonst nur für Korrektoren
SheetSolution: Lösung SheetSolution: Lösung
SheetSolutionFrom: Lösung ab SheetSolutionFrom: Lösung ab
SheetMarking: Hinweise für Korrektoren SheetMarking: Hinweise für Korrektoren
@ -2061,3 +2063,34 @@ ProfileRemark: Hinweis
ProfileGroupSubmissionDates: Bei Gruppenabgaben wird kein Datum angezeigt, wenn Sie die Gruppenabgabe nie selbst hochgeladen haben. ProfileGroupSubmissionDates: Bei Gruppenabgaben wird kein Datum angezeigt, wenn Sie die Gruppenabgabe nie selbst hochgeladen haben.
ProfileCorrectorRemark: Die oberhalb angezeigte Tabelle zeigt nur prinzipielle Einteilungen als Korrektor zu einem Übungsblatt. Auch ohne Einteilung können Korrekturen einzeln zugewiesen werden, welche hier dann nicht aufgeführt werden. ProfileCorrectorRemark: Die oberhalb angezeigte Tabelle zeigt nur prinzipielle Einteilungen als Korrektor zu einem Übungsblatt. Auch ohne Einteilung können Korrekturen einzeln zugewiesen werden, welche hier dann nicht aufgeführt werden.
ProfileCorrections: Auflistung aller zugewiesenen Korrekturen ProfileCorrections: Auflistung aller zugewiesenen Korrekturen
GroupSizeNotNatural: „Gruppengröße“ muss eine natürliche Zahl sein
AmbiguousEmail: E-Mail Adresse nicht eindeutig
CourseDescriptionPlaceholder: Bitte mindestens die Modulbeschreibung angeben
CourseHomepageExternalPlaceholder: Optionale externe URL
PointsPlaceholder: Punktezahl
RFC1766: RFC1766-Sprachcode
TermShort: Kürzel
TermCourseCount: Kurse
TermStart: Semesteranfang
TermEnd: Semesterende
TermStartMustMatchName: Jahreszahl im Namenskürzel stimmt nicht mit Semesterbeginn überein.
TermEndMustBeAfterStart: Semester darf nicht enden, bevor es beginnt.
TermLectureEndMustBeAfterStart: Vorlesungszeit muss vor ihrem Ende anfgangen.
TermStartMustBeBeforeLectureStart: Semester muss vor der Vorlesungszeit beginnen.
TermEndMustBeAfterLectureEnd: Vorlesungszeit muss vor dem Semester enden.
AdminPageEmpty: Diese Seite soll eine Übersichtsseite für Administratoren werden. Aktuell finden sich hier nur Links zu wichtigen Administrator-Funktionalitäten.
HaveCorrectorAccess sheetName@SheetName: Sie haben Korrektor-Zugang zu #{original sheetName}.
FavouritesPlaceholder: Anzahl Favoriten
FavouritesNotNatural: Anzahl der Favoriten muss eine natürliche Zahl sein!
FavouritesSemestersPlaceholder: Anzahl Semester
FavouritesSemestersNotNatural: Anzahl der Favoriten-Semester muss eine natürliche Zahl sein!
ProfileTitle: Benutzereinstellungen
GlossaryTitle: Begriffsverzeichnis
MenuGlossary: Begriffsverzeichnis
Applicant: Bewerber
CourseParticipant: Kursteilnehmer

View File

@ -1,2 +1,146 @@
Logo: Uni2work
BtnSubmit: Submit
BtnAbort: Abort
BtnDelete: Delete
BtnRegister: Register
BtnDeregister: Deregister
BtnCourseRegister: Enrol for course
BtnCourseDeregister: Leave course
BtnCourseApply: Apply for course
BtnCourseRetractApplication: Retract application
BtnExamRegister: Enrol for exam
BtnExamDeregister: Leave exam
BtnHijack: Hijack session
BtnSave: Save
PressSaveToSave: Changes will only be saved after clicking "Save".
BtnHandIn: Hand in submission
BtnCandidatesInfer: Infer mapping
BtnCandidatesDeleteConflicts: Delete conflicts
BtnCandidatesDeleteAll: Delete all observations
BtnResetTokens: Invalidate tokens
BtnLecInvAccept: Accept
BtnLecInvDecline: Decline
BtnCorrInvAccept: Accept
BtnCorrInvDecline: Decline
BtnSubmissionsAssign: Assign submissions automatically
Aborted: Aborted
Remarks: Remarks
Registered: Registered
RegisteredSince: Registered since
NotRegistered: Note enrolled for this course
Registration: Registration
RegisterFrom: Registration starts
RegisterTo: Registration ends
DeRegUntil: Deregistration until
RegisterRetry: You haven't been enrolled. Press "Enrol for course" to enrol
CourseRegistrationInterval: Registration
CourseDirectRegistrationInterval: Direct registration
CourseDeregisterUntil time: Deregistration only until #{time}
GenericKey: Key
GenericShort: Shorthand
GenericIsNew: New
GenericHasConflict: Conflict
GenericBack: Back
GenericChange: Change
GenericNumChange: +/-
GenericMin: Min
GenericAvg: Avg
GenericMax: Max
GenericAll: All
SummerTerm year: Summer semester #{year}
WinterTerm year: Winter semester #{year}/#{succ year}
SummerTermShort year: Summer #{year}
WinterTermShort year: Winter #{year}/#{mod (succ year) 100}
PSLimitNonPositive: “pagesize” must be greater than zero
Page num: #{num}
TermsHeading: Semesters
TermCurrent: Current semester
TermEditHeading: Edit semester
TermEditTid tid: Edit semester #{tid}
TermEdited tid: Successfully edited semester #{tid}
TermNewTitle: Edit/create semester
InvalidInput: Invalid input
Term: Semester
TermPlaceholder: (W|S)<four digit year>
TermStartDay: Starting day
TermStartDayTooltip: Usually 1st of April or 1st of October
TermEndDay: Last day
TermEndDayTooltip: Usually 30th of September or 31st of March
TermHolidays: Legal holidays
TermHolidayPlaceholder: Legal holiday
TermLectureStart: Lectures start
TermLectureEnd: Lectures end
TermLectureEndTooltip: Summer semesters are usually 14 weeks; winter semesters 15
TermActive: Active
SchoolListHeading: Departments
SchoolHeading school: #{school}
LectureStart: Lectures start
Course: Course
CourseShort: Shorthand
CourseCapacity: Capacity
CourseCapacityTip: Maximum permissable number of enrollments for this course; leave empty for unlimited capacity
CourseNoCapacity: Course has reached maximum capacity
TutorialNoCapacity: Tutorial has reached maximum capacity
CourseNotEmpty: There are currently no participants enrolled for this course.
CourseRegistration: Registration
CourseRegisterOpen: Registration is open
CourseRegisterOk: Successfully enrolled for course
CourseDeregisterOk: Successfully left course
CourseApplyOk: Successfully applied for course
CourseRetractApplyOk: Successfully retracted application for course
CourseDeregisterLecturerTip: If you deregister the participant you might loose access to this data
CourseStudyFeature: Associated subject
CourseStudyFeatureTip: For information purposes only (visible to course administrators)
CourseStudyFeatureUpdated: Successfully updated associated subject
CourseStudyFeatureNone: No associated subject
CourseTutorial: Tutorial
CourseSecretWrong: Wrong password
CourseSecret: Access password
CourseEditOk tid ssh csh: Successfully edited course #{tid}-#{ssh}-#{csh}
CourseNewDupShort tid ssh csh: Could not create course #{tid}-#{ssh}-#{csh}. Another course with shorthand #{csh} already exists for the given semester and school.
CourseEditDupShort tid ssh csh: Could not edit course #{tid}-#{ssh}-#{csh}. Another course with shorthand #{csh} already exists for the given semester and school.
FFSheetName: Name
TermCourseListHeading tid: Courses #{tid}
TermSchoolCourseListHeading tid school: Courses #{tid}, #{school}
CourseListTitle: All courses
TermCourseListTitle tid: Courses #{tid}
TermSchoolCourseListTitle tid school: Courses #{tid}, #{school}
CourseNewHeading: Create new course
CourseEditHeading tid ssh csh: Edit course #{tid}-#{ssh}-#{csh}
CourseEditTitle: Edit/Create course
CourseMembers: Participants
CourseMemberOf: Participant of
CourseAssociatedWith: associated with
CourseMembersCount n: #{n}
CourseMembersCountLimited n max: #{n}/#{max}
CourseMembersCountOf n mbNum: #{n} #{maybeToMessage "of " mbNum " "}participants
CourseName: Title
CourseDescription: Description
CourseDescriptionTip: You may use arbitrary Html-Markup
CourseHomepageExternal: External homepage
CourseShorthand: Shorthand
CourseShorthandUnique: Needs to be unique within school and semester. Will be used verbatim within the url of the course page.
CourseSemester: Semester
CourseSchool: Department
CourseSchoolShort: Department
CourseSecretTip: Enrollment for this course will require the password, if set
CourseSecretFormat: Arbitrary string
CourseRegisterFromTip: When left empty students will not be able to enroll themselves
CourseRegisterToTip: May be left empty to allow enrollment indefinitely
CourseDeregisterUntilTip: Participants may deregister from immediately after registration starts up to this time. May be left empty to allow deregistration indefinitely.
CourseFilterSearch: Text search
CourseFilterRegistered: Registered
MenuLanguage: Language MenuLanguage: Language
LanguageChanged: Language changed successfully LanguageChanged: Language changed successfully

1
routes
View File

@ -63,6 +63,7 @@
/info/lecturer InfoLecturerR GET !lecturer /info/lecturer InfoLecturerR GET !lecturer
/info/data DataProtR GET !free /info/data DataProtR GET !free
/info/allocation InfoAllocationR GET !free /info/allocation InfoAllocationR GET !free
/info/glossary GlossaryR GET !free
/impressum ImpressumR GET !free /impressum ImpressumR GET !free
/version VersionR GET !free /version VersionR GET !free

View File

@ -13,6 +13,7 @@ import qualified Data.CaseInsensitive as CI
data DummyMessage = MsgDummyIdent data DummyMessage = MsgDummyIdent
| MsgDummyIdentPlaceholder
| MsgDummyNoFormData | MsgDummyNoFormData
deriving (Eq, Ord, Enum, Bounded, Read, Show, Generic, Typeable) deriving (Eq, Ord, Enum, Bounded, Read, Show, Generic, Typeable)
@ -24,7 +25,9 @@ dummyForm :: ( RenderMessage (HandlerSite m) FormMessage
, Button (HandlerSite m) ButtonSubmit , Button (HandlerSite m) ButtonSubmit
, MonadHandler m , MonadHandler m
) => AForm m (CI Text) ) => AForm m (CI Text)
dummyForm = areq (ciField & addDatalist userList) (fslI MsgDummyIdent & noAutocomplete) Nothing dummyForm = wFormToAForm $ do
mr <- getMessageRender
aFormToWForm $ areq (ciField & addDatalist userList) (fslpI MsgDummyIdent (mr MsgDummyIdentPlaceholder) & noAutocomplete) Nothing
where where
userList = fmap mkOptionList . runDB $ withReaderT projectBackend (map toOption <$> selectList [] [Asc UserIdent] :: ReaderT SqlBackend _ [Option UserIdent]) userList = fmap mkOptionList . runDB $ withReaderT projectBackend (map toOption <$> selectList [] [Asc UserIdent] :: ReaderT SqlBackend _ [Option UserIdent])
toOption (Entity _ User{..}) = Option userDisplayName userIdent (CI.original userIdent) toOption (Entity _ User{..}) = Option userDisplayName userIdent (CI.original userIdent)

View File

@ -36,6 +36,7 @@ data CampusLogin = CampusLogin
data CampusMessage = MsgCampusIdentPlaceholder data CampusMessage = MsgCampusIdentPlaceholder
| MsgCampusIdent | MsgCampusIdent
| MsgCampusPassword | MsgCampusPassword
| MsgCampusPasswordPlaceholder
| MsgCampusSubmit | MsgCampusSubmit
| MsgCampusInvalidCredentials | MsgCampusInvalidCredentials
deriving (Eq, Ord, Enum, Bounded, Read, Show, Generic, Typeable) deriving (Eq, Ord, Enum, Bounded, Read, Show, Generic, Typeable)
@ -129,7 +130,7 @@ campusForm = do
MsgRenderer mr <- getMsgRenderer MsgRenderer mr <- getMsgRenderer
ident <- wreq ciField (fslpI MsgCampusIdent (mr MsgCampusIdentPlaceholder) & addAttr "autofocus" "") Nothing ident <- wreq ciField (fslpI MsgCampusIdent (mr MsgCampusIdentPlaceholder) & addAttr "autofocus" "") Nothing
password <- wreq passwordField (fslI MsgCampusPassword) Nothing password <- wreq passwordField (fslpI MsgCampusPassword (mr MsgCampusPasswordPlaceholder)) Nothing
return $ CampusLogin return $ CampusLogin
<$> ident <$> ident

View File

@ -22,7 +22,9 @@ data HashLogin = HashLogin
} deriving (Generic, Typeable) } deriving (Generic, Typeable)
data PWHashMessage = MsgPWHashIdent data PWHashMessage = MsgPWHashIdent
| MsgPWHashIdentPlaceholder
| MsgPWHashPassword | MsgPWHashPassword
| MsgPWHashPasswordPlaceholder
deriving (Eq, Ord, Enum, Bounded, Read, Show, Generic, Typeable) deriving (Eq, Ord, Enum, Bounded, Read, Show, Generic, Typeable)
@ -30,9 +32,11 @@ hashForm :: ( RenderMessage (HandlerSite m) FormMessage
, RenderMessage (HandlerSite m) PWHashMessage , RenderMessage (HandlerSite m) PWHashMessage
, MonadHandler m , MonadHandler m
) => AForm m HashLogin ) => AForm m HashLogin
hashForm = HashLogin hashForm = wFormToAForm $ do
<$> areq ciField (fslpI MsgPWHashIdent "Identifikation") Nothing mr <- getMessageRender
<*> areq passwordField (fslpI MsgPWHashPassword "Passwort") Nothing aFormToWForm $ HashLogin
<$> areq ciField (fslpI MsgPWHashIdent (mr MsgPWHashIdentPlaceholder)) Nothing
<*> areq passwordField (fslpI MsgPWHashPassword (mr MsgPWHashPasswordPlaceholder)) Nothing
hashLogin :: forall site. hashLogin :: forall site.

View File

@ -2182,7 +2182,9 @@ instance YesodBreadcrumbs UniWorX where
if if
| mayList -> i18nCrumb MsgBreadcrumbSystemMessage $ Just MessageListR | mayList -> i18nCrumb MsgBreadcrumbSystemMessage $ Just MessageListR
| otherwise -> i18nCrumb MsgBreadcrumbSystemMessage $ Just HomeR | otherwise -> i18nCrumb MsgBreadcrumbSystemMessage $ Just HomeR
breadcrumb (MessageListR) = i18nCrumb MsgMenuMessageList $ Just AdminR breadcrumb MessageListR = i18nCrumb MsgMenuMessageList $ Just AdminR
breadcrumb GlossaryR = i18nCrumb MsgMenuGlossary $ Just InfoR
-- 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]
@ -2480,6 +2482,14 @@ pageActions (InfoR) = [
, menuItemModal = False , menuItemModal = False
, menuItemAccessCallback' = return True , menuItemAccessCallback' = return True
} }
, MenuItem
{ menuItemType = PageActionPrime
, menuItemLabel = MsgMenuGlossary
, menuItemIcon = Nothing
, menuItemRoute = SomeRoute GlossaryR
, menuItemModal = False
, menuItemAccessCallback' = return True
}
] ]
pageActions (VersionR) = [ pageActions (VersionR) = [
MenuItem MenuItem

View File

@ -33,10 +33,7 @@ getAdminR :: Handler Html
getAdminR = -- do getAdminR = -- do
siteLayoutMsg MsgAdminHeading $ do siteLayoutMsg MsgAdminHeading $ do
setTitleI MsgAdminHeading setTitleI MsgAdminHeading
[whamlet| i18n MsgAdminPageEmpty
This shall become the Administrators' overview page.
Its current purpose is to provide links to some important admin functions
|]
-- BEGIN - Buttons needed only here -- BEGIN - Buttons needed only here
data ButtonCreate = CreateMath | CreateInf -- Dummy for Example data ButtonCreate = CreateMath | CreateInf -- Dummy for Example
@ -74,7 +71,7 @@ emailTestForm = (,)
makeDemoForm :: Int -> Form (Int,Bool,Double) makeDemoForm :: Int -> Form (Int,Bool,Double)
makeDemoForm n = identifyForm ("adminTestForm" :: Text) $ \html -> do makeDemoForm n = identifyForm ("adminTestForm" :: Text) $ \html -> do
(result, widget) <- flip (renderAForm FormStandard) html $ (,,) (result, widget) <- flip (renderAForm FormStandard) html $ (,,)
<$> areq (minIntField n "Zahl") (fromString $ "Ganzzahl > " ++ show n) Nothing <$> areq (minIntFieldI n ("Zahl" :: Text)) (fromString $ "Ganzzahl > " ++ show n) Nothing
<* aformSection MsgFormBehaviour <* aformSection MsgFormBehaviour
<*> areq checkBoxField "Muss nächste Zahl größer sein?" (Just True) <*> areq checkBoxField "Muss nächste Zahl größer sein?" (Just True)
<*> areq doubleField "Fliesskommazahl" Nothing <*> areq doubleField "Fliesskommazahl" Nothing
@ -254,8 +251,9 @@ postAdminTestR = do
getAdminErrMsgR, postAdminErrMsgR :: Handler Html getAdminErrMsgR, postAdminErrMsgR :: Handler Html
getAdminErrMsgR = postAdminErrMsgR getAdminErrMsgR = postAdminErrMsgR
postAdminErrMsgR = do postAdminErrMsgR = do
MsgRenderer mr <- getMsgRenderer
((ctResult, ctView), ctEncoding) <- runFormPost . renderAForm FormStandard $ ((ctResult, ctView), ctEncoding) <- runFormPost . renderAForm FormStandard $
unTextarea <$> areq textareaField (fslpI MsgErrMsgCiphertext "Ciphertext") Nothing unTextarea <$> areq textareaField (fslpI MsgErrMsgCiphertext (mr MsgErrMsgCiphertext)) Nothing
plaintext <- formResultMaybe ctResult $ exceptT (\err -> Nothing <$ addMessageI Error err) (return . Just) . (encodedSecretBoxOpen :: Text -> ExceptT EncodedSecretBoxException Handler Value) plaintext <- formResultMaybe ctResult $ exceptT (\err -> Nothing <$ addMessageI Error err) (return . Just) . (encodedSecretBoxOpen :: Text -> ExceptT EncodedSecretBoxException Handler Value)

View File

@ -714,13 +714,14 @@ postCorrectionR tid ssh csh shn cid = do
results <- runDB $ correctionData tid ssh csh shn sub results <- runDB $ correctionData tid ssh csh shn sub
MsgRenderer mr <- getMsgRenderer
case results of case results of
[(Entity _ Course{..}, Entity _ Sheet{..}, Entity _ subm@Submission{..}, corrector)] -> do [(Entity _ Course{..}, Entity _ Sheet{..}, Entity _ subm@Submission{..}, corrector)] -> do
let ratingComment = fmap Text.strip submissionRatingComment >>= (\c -> c <$ guard (not $ null c)) let ratingComment = fmap Text.strip submissionRatingComment >>= (\c -> c <$ guard (not $ null c))
pointsForm = case sheetType of pointsForm = case sheetType of
NotGraded -> pure Nothing NotGraded -> pure Nothing
_otherwise -> aopt (pointsFieldMax $ preview (_grading . _maxPoints) sheetType) _otherwise -> aopt (pointsFieldMax $ preview (_grading . _maxPoints) sheetType)
(fslpI MsgRatingPoints "Punktezahl" & setTooltip sheetType) (fslpI MsgRatingPoints (mr MsgPointsPlaceholder) & setTooltip sheetType)
(Just submissionRatingPoints) (Just submissionRatingPoints)
((corrResult, corrForm'), corrEncoding) <- runFormPost . identifyForm FIDcorrection . renderAForm FormStandard $ (,,) ((corrResult, corrForm'), corrEncoding) <- runFormPost . identifyForm FIDcorrection . renderAForm FormStandard $ (,,)
@ -776,7 +777,6 @@ postCorrectionR tid ssh csh shn cid = do
addMessageI Success MsgRatingFilesUpdated addMessageI Success MsgRatingFilesUpdated
redirect $ CSubmissionR tid ssh csh shn cid CorrectionR redirect $ CSubmissionR tid ssh csh shn cid CorrectionR
mr <- getMessageRender
let sheetTypeDesc = mr sheetType let sheetTypeDesc = mr sheetType
heading = MsgCorrectionHead tid ssh csh shn cid heading = MsgCorrectionHead tid ssh csh shn cid
headingWgt = [whamlet| headingWgt = [whamlet|
@ -868,9 +868,10 @@ postCorrectionsCreateR = do
, optionInternalValue = sid , optionInternalValue = sid
, optionExternalValue = toPathPiece (cID :: CryptoUUIDSheet) , optionExternalValue = toPathPiece (cID :: CryptoUUIDSheet)
} }
MsgRenderer mr <- getMsgRenderer
((pseudonymRes, pseudonymWidget), pseudonymEncoding) <- runFormPost . renderAForm FormStandard $ (,) ((pseudonymRes, pseudonymWidget), pseudonymEncoding) <- runFormPost . renderAForm FormStandard $ (,)
<$> areq (selectField sheetOptions) (fslI MsgPseudonymSheet) Nothing <$> areq (selectField sheetOptions) (fslI MsgPseudonymSheet) Nothing
<*> (textToList <$> areq textareaField (fslpI MsgCorrectionPseudonyms "Pseudonyme" & setTooltip MsgCorrectionPseudonymsTip) Nothing) <*> (textToList <$> areq textareaField (fslpI MsgCorrectionPseudonyms (mr MsgPseudonyms) & setTooltip MsgCorrectionPseudonymsTip) Nothing)
case pseudonymRes of case pseudonymRes of
FormMissing -> return () FormMissing -> return ()

View File

@ -256,7 +256,6 @@ makeCourseForm miButtonAction template = identifyForm FIDcourse . validateFormDB
optionalActionW' (bool mforcedJust mpopt mayChange) allocationForm' (fslI MsgCourseAllocationParticipate & setTooltip MsgCourseAllocationParticipateTip) (is _Just . cfAllocation <$> template) optionalActionW' (bool mforcedJust mpopt mayChange) allocationForm' (fslI MsgCourseAllocationParticipate & setTooltip MsgCourseAllocationParticipateTip) (is _Just . cfAllocation <$> template)
-- TODO: internationalization
-- let autoUnzipInfo = [|Entpackt hochgeladene Zip-Dateien (*.zip) automatisch und fügt den Inhalt dem Stamm-Verzeichnis der Abgabe hinzu. TODO|] -- let autoUnzipInfo = [|Entpackt hochgeladene Zip-Dateien (*.zip) automatisch und fügt den Inhalt dem Stamm-Verzeichnis der Abgabe hinzu. TODO|]
(result, widget) <- flip (renderAForm FormStandard) html $ CourseForm (result, widget) <- flip (renderAForm FormStandard) html $ CourseForm
@ -267,9 +266,9 @@ makeCourseForm miButtonAction template = identifyForm FIDcourse . validateFormDB
& setTooltip MsgCourseShorthandUnique) (cfShort <$> template) & setTooltip MsgCourseShorthandUnique) (cfShort <$> template)
<*> areq (schoolFieldFor userSchools) (fslI MsgCourseSchool) (cfSchool <$> template) <*> areq (schoolFieldFor userSchools) (fslI MsgCourseSchool) (cfSchool <$> template)
<*> areq termsField (fslI MsgCourseSemester) (cfTerm <$> template) <*> areq termsField (fslI MsgCourseSemester) (cfTerm <$> template)
<*> aopt htmlField (fslpI MsgCourseDescription "Bitte mindestens die Modulbeschreibung angeben" <*> aopt htmlField (fslpI MsgCourseDescription (mr MsgCourseDescriptionPlaceholder)
& setTooltip MsgCourseDescriptionTip) (cfDesc <$> template) & setTooltip MsgCourseDescriptionTip) (cfDesc <$> template)
<*> aopt (urlField & cfStrip) (fslpI MsgCourseHomepageExternal "Optionale externe URL") <*> aopt (urlField & cfStrip) (fslpI MsgCourseHomepageExternal (mr MsgCourseHomepageExternalPlaceholder))
(cfLink <$> template) (cfLink <$> template)
<*> apopt checkBoxField (fslI MsgMaterialFree) (cfMatFree <$> template) <*> apopt checkBoxField (fslI MsgMaterialFree) (cfMatFree <$> template)
<* aformSection MsgCourseFormSectionRegistration <* aformSection MsgCourseFormSectionRegistration

View File

@ -3,6 +3,9 @@ module Handler.Info where
import Import import Import
import Handler.Utils import Handler.Utils
import qualified Data.Map as Map
import qualified Data.CaseInsensitive as CI
import Development.GitRev import Development.GitRev
-- | Versionsgeschichte -- | Versionsgeschichte
@ -67,3 +70,21 @@ getInfoLecturerR =
if currentTime > expiryTime if currentTime > expiryTime
then mempty then mempty
else toWidget [whamlet| ^{iconTooltip tooltipNew (Just IconNew) False} |] else toWidget [whamlet| ^{iconTooltip tooltipNew (Just IconNew) False} |]
getGlossaryR :: Handler Html
getGlossaryR =
siteLayoutMsg' MsgGlossaryTitle $ do
setTitleI MsgGlossaryTitle
MsgRenderer mr <- getMsgRenderer
let
entries' = sortOn (CI.mk . view _2) $ do
(k, v) <- Map.toList entries
msg <- maybeToList $ Map.lookup k msgMap
return (k, mr msg, v)
$(widgetFile "glossary")
where
entries = $(i18nWidgetFiles "glossary")
msgMap = Map.fromList
[ ("applicant" , MsgApplicant )
, ("course-participant", MsgCourseParticipant)
]

View File

@ -79,15 +79,16 @@ instance RenderMessage UniWorX NotificationTriggerKind where
makeSettingForm :: Maybe SettingsForm -> Form SettingsForm makeSettingForm :: Maybe SettingsForm -> Form SettingsForm
makeSettingForm template html = do makeSettingForm template html = do
MsgRenderer mr <- getMsgRenderer
(result, widget) <- flip (renderAForm FormStandard) html $ SettingsForm (result, widget) <- flip (renderAForm FormStandard) html $ SettingsForm
<$ aformSection MsgFormPersonalAppearance <$ aformSection MsgFormPersonalAppearance
<*> areq (textField & cfStrip) (fslI MsgUserDisplayName & setTooltip MsgUserDisplayNameRulesBelow) (stgDisplayName <$> template) <*> areq (textField & cfStrip) (fslI MsgUserDisplayName & setTooltip MsgUserDisplayNameRulesBelow) (stgDisplayName <$> template)
<*> areq (emailField & cfStrip & cfCI) (fslI MsgUserDisplayEmail & setTooltip MsgUserDisplayEmailTip) (stgDisplayEmail <$> template) <*> areq (emailField & cfStrip & cfCI) (fslI MsgUserDisplayEmail & setTooltip MsgUserDisplayEmailTip) (stgDisplayEmail <$> template)
<* aformSection MsgFormCosmetics <* aformSection MsgFormCosmetics
<*> areq (natFieldI $ MsgNatField "Favoriten") <*> areq (natFieldI MsgFavouritesNotNatural)
(fslpI MsgFavourites "Anzahl Favoriten" & setTooltip MsgFavouritesTip) (stgMaxFavourites <$> template) (fslpI MsgFavourites (mr MsgFavouritesPlaceholder) & setTooltip MsgFavouritesTip) (stgMaxFavourites <$> template)
<*> areq (natFieldI $ MsgNatField "Favoriten-Semester") <*> areq (natFieldI MsgFavouritesSemestersNotNatural)
(fslpI MsgFavouriteSemesters "Anzahl Semester") (stgMaxFavouriteTerms <$> template) (fslpI MsgFavouriteSemesters (mr MsgFavouritesSemestersPlaceholder)) (stgMaxFavouriteTerms <$> template)
<*> areq (selectField . return $ mkOptionList themeList) <*> areq (selectField . return $ mkOptionList themeList)
(fslI MsgTheme) { fsId = Just "theme-select" } (stgTheme <$> template) (fslI MsgTheme) { fsId = Just "theme-select" } (stgTheme <$> template)
<*> areq (selectField $ dateTimeFormatOptions SelFormatDateTime) (fslI MsgDateTimeFormat) (stgDateTime <$> template) <*> areq (selectField $ dateTimeFormatOptions SelFormatDateTime) (fslI MsgDateTimeFormat) (stgDateTime <$> template)
@ -318,7 +319,7 @@ postProfileR = do
tResetTime <- traverse (formatTime SelFormatDateTime) userTokensIssuedAfter tResetTime <- traverse (formatTime SelFormatDateTime) userTokensIssuedAfter
siteLayout [whamlet|_{MsgProfileFor} ^{nameWidget userDisplayName userSurname}|] $ do siteLayout [whamlet|_{MsgProfileFor} ^{nameWidget userDisplayName userSurname}|] $ do
setTitle . toHtml $ "Profil " <> userIdent setTitleI MsgProfileTitle
let settingsForm = let settingsForm =
wrapForm formWidget FormSettings wrapForm formWidget FormSettings
{ formMethod = POST { formMethod = POST

View File

@ -91,7 +91,7 @@ makeSheetForm msId template = identifyForm FIDsheet $ \html -> do
oldFileIds <- (return.) <$> case msId of oldFileIds <- (return.) <$> case msId of
Nothing -> return $ partitionFileType mempty Nothing -> return $ partitionFileType mempty
(Just sId) -> liftHandler $ runDB $ getFtIdMap sId (Just sId) -> liftHandler $ runDB $ getFtIdMap sId
mr <- getMsgRenderer mr'@(MsgRenderer mr) <- getMsgRenderer
ctime <- ceilingQuarterHour <$> liftIO getCurrentTime ctime <- ceilingQuarterHour <$> liftIO getCurrentTime
(result, widget) <- flip (renderAForm FormStandard) html $ SheetForm (result, widget) <- flip (renderAForm FormStandard) html $ SheetForm
<$> areq (textField & cfStrip & cfCI) (fslI MsgSheetName) (sfName <$> template) <$> areq (textField & cfStrip & cfCI) (fslI MsgSheetName) (sfName <$> template)
@ -103,9 +103,9 @@ makeSheetForm msId template = identifyForm FIDsheet $ \html -> do
& setTooltip MsgSheetActiveFromTip) & setTooltip MsgSheetActiveFromTip)
(sfActiveFrom <$> template) (sfActiveFrom <$> template)
<*> areq utcTimeField (fslI MsgSheetActiveTo) (sfActiveTo <$> template) <*> areq utcTimeField (fslI MsgSheetActiveTo) (sfActiveTo <$> template)
<*> aopt utcTimeField (fslpI MsgSheetHintFrom "Datum, sonst nur für Korrektoren" <*> aopt utcTimeField (fslpI MsgSheetHintFrom (mr MsgSheetHintFromPlaceholder)
& setTooltip MsgSheetHintFromTip) (sfHintFrom <$> template) & setTooltip MsgSheetHintFromTip) (sfHintFrom <$> template)
<*> aopt utcTimeField (fslpI MsgSheetSolutionFrom "Datum, sonst nur für Korrektoren" <*> aopt utcTimeField (fslpI MsgSheetSolutionFrom (mr MsgSheetSolutionFromPlaceholder)
& setTooltip MsgSheetSolutionFromTip) (sfSolutionFrom <$> template) & setTooltip MsgSheetSolutionFromTip) (sfSolutionFrom <$> template)
<* aformSection MsgSheetFormFiles <* aformSection MsgSheetFormFiles
<*> aopt (multiFileField $ oldFileIds SheetExercise) (fslI MsgSheetExercise) (sfSheetF <$> template) <*> aopt (multiFileField $ oldFileIds SheetExercise) (fslI MsgSheetExercise) (sfSheetF <$> template)
@ -124,7 +124,7 @@ makeSheetForm msId template = identifyForm FIDsheet $ \html -> do
<*> aopt htmlField (fslpI MsgSheetMarking "Html") (sfMarkingText <$> template) <*> aopt htmlField (fslpI MsgSheetMarking "Html") (sfMarkingText <$> template)
return $ case result of return $ case result of
FormSuccess sheetResult FormSuccess sheetResult
| errorMsgs <- validateSheet mr sheetResult | errorMsgs <- validateSheet mr' sheetResult
, not $ null errorMsgs -> , not $ null errorMsgs ->
(FormFailure errorMsgs, widget) (FormFailure errorMsgs, widget)
_ -> (result, widget) _ -> (result, widget)
@ -923,5 +923,5 @@ postSCorrInviteR = invitationR correctorInvitationConfig
getSIsCorrR :: TermId -> SchoolId -> CourseShorthand -> SheetName -> Handler Html getSIsCorrR :: TermId -> SchoolId -> CourseShorthand -> SheetName -> Handler Html
-- NOTE: The route SIsCorrR is only used to verfify corrector access rights to given sheet! -- NOTE: The route SIsCorrR is only used to verfify corrector access rights to given sheet!
getSIsCorrR _ _ _ shn = do getSIsCorrR _ _ _ shn = do
defaultLayout $ [whamlet|You have corrector access to #{shn}.|] defaultLayout . i18n $ MsgHaveCorrectorAccess shn

View File

@ -23,6 +23,7 @@ postMessageR cID = do
Nothing -> (systemMessageSummary, systemMessageContent) Nothing -> (systemMessageSummary, systemMessageContent)
Just SystemMessageTranslation{..} -> (systemMessageTranslationSummary, systemMessageTranslationContent) Just SystemMessageTranslation{..} -> (systemMessageTranslationSummary, systemMessageTranslationContent)
MsgRenderer mr <- getMsgRenderer
let let
mkForm = do mkForm = do
((modifyRes, modifyView), modifyEnctype) <- runFormPost . identifyForm FIDSystemMessageModify . renderAForm FormStandard ((modifyRes, modifyView), modifyEnctype) <- runFormPost . identifyForm FIDSystemMessageModify . renderAForm FormStandard
@ -31,9 +32,9 @@ postMessageR cID = do
<*> aopt utcTimeField (fslI MsgSystemMessageTo) (Just systemMessageTo) <*> aopt utcTimeField (fslI MsgSystemMessageTo) (Just systemMessageTo)
<*> areq checkBoxField (fslI MsgSystemMessageAuthenticatedOnly) (Just systemMessageAuthenticatedOnly) <*> areq checkBoxField (fslI MsgSystemMessageAuthenticatedOnly) (Just systemMessageAuthenticatedOnly)
<*> areq (selectField optionsFinite) (fslI MsgSystemMessageSeverity) (Just systemMessageSeverity) <*> areq (selectField optionsFinite) (fslI MsgSystemMessageSeverity) (Just systemMessageSeverity)
<*> areq (langField False) (fslpI MsgSystemMessageLanguage "RFC1766-Sprachcode") (Just systemMessageDefaultLanguage) <*> areq (langField False) (fslpI MsgSystemMessageLanguage (mr MsgRFC1766)) (Just systemMessageDefaultLanguage)
<*> areq htmlField' (fslpI MsgSystemMessageContent "HTML") (Just systemMessageContent) <*> areq htmlField' (fslpI MsgSystemMessageContent "Html") (Just systemMessageContent)
<*> aopt htmlField' (fslpI MsgSystemMessageSummary "HTML") (Just systemMessageSummary) <*> aopt htmlField' (fslpI MsgSystemMessageSummary "Html") (Just systemMessageSummary)
ts <- runDB $ selectList [ SystemMessageTranslationMessage ==. smId ] [Asc SystemMessageTranslationLanguage] ts <- runDB $ selectList [ SystemMessageTranslationMessage ==. smId ] [Asc SystemMessageTranslationLanguage]
let ts' = Map.fromList $ (systemMessageTranslationLanguage . entityVal &&& id) <$> ts let ts' = Map.fromList $ (systemMessageTranslationLanguage . entityVal &&& id) <$> ts
@ -45,9 +46,9 @@ postMessageR cID = do
<$> fmap (Entity tId) <$> fmap (Entity tId)
( SystemMessageTranslation ( SystemMessageTranslation
<$> pure systemMessageTranslationMessage <$> pure systemMessageTranslationMessage
<*> areq (langField False) (fslpI MsgSystemMessageLanguage "RFC1766-Sprachcode") (Just systemMessageTranslationLanguage) <*> areq (langField False) (fslpI MsgSystemMessageLanguage (mr MsgRFC1766)) (Just systemMessageTranslationLanguage)
<*> areq htmlField' (fslpI MsgSystemMessageContent "HTML") (Just systemMessageTranslationContent) <*> areq htmlField' (fslpI MsgSystemMessageContent "Html") (Just systemMessageTranslationContent)
<*> aopt htmlField' (fslpI MsgSystemMessageSummary "HTML") (Just systemMessageTranslationSummary) <*> aopt htmlField' (fslpI MsgSystemMessageSummary "Html") (Just systemMessageTranslationSummary)
) )
<*> combinedButtonFieldF "" <*> combinedButtonFieldF ""
@ -56,9 +57,9 @@ postMessageR cID = do
((addTransRes, addTransView), addTransEnctype) <- runFormPost . identifyForm FIDSystemMessageAddTranslation . renderAForm FormStandard ((addTransRes, addTransView), addTransEnctype) <- runFormPost . identifyForm FIDSystemMessageAddTranslation . renderAForm FormStandard
$ SystemMessageTranslation $ SystemMessageTranslation
<$> pure smId <$> pure smId
<*> areq (langField False) (fslpI MsgSystemMessageLanguage "RFC1766-Sprachcode") Nothing <*> areq (langField False) (fslpI MsgSystemMessageLanguage (mr MsgRFC1766)) Nothing
<*> areq htmlField' (fslpI MsgSystemMessageContent "HTML") Nothing <*> areq htmlField' (fslpI MsgSystemMessageContent "Html") Nothing
<*> aopt htmlField' (fslpI MsgSystemMessageSummary "HTML") Nothing <*> aopt htmlField' (fslpI MsgSystemMessageSummary "Html") Nothing
formResult modifyRes $ modifySystemMessage smId formResult modifyRes $ modifySystemMessage smId
@ -252,14 +253,15 @@ postMessageListR = do
FormSuccess (_, _selection) -- prop> null _selection FormSuccess (_, _selection) -- prop> null _selection
-> addMessageI Error MsgSystemMessageEmptySelection -> addMessageI Error MsgSystemMessageEmptySelection
MsgRenderer mr <- getMsgRenderer
((addRes, addView), addEncoding) <- runFormPost . identifyForm FIDSystemMessageAdd . renderAForm FormStandard $ SystemMessage ((addRes, addView), addEncoding) <- runFormPost . identifyForm FIDSystemMessageAdd . renderAForm FormStandard $ SystemMessage
<$> aopt utcTimeField (fslI MsgSystemMessageFrom) Nothing <$> aopt utcTimeField (fslI MsgSystemMessageFrom) Nothing
<*> aopt utcTimeField (fslI MsgSystemMessageTo) Nothing <*> aopt utcTimeField (fslI MsgSystemMessageTo) Nothing
<*> areq checkBoxField (fslI MsgSystemMessageAuthenticatedOnly) Nothing <*> areq checkBoxField (fslI MsgSystemMessageAuthenticatedOnly) Nothing
<*> areq (selectField optionsFinite) (fslI MsgSystemMessageSeverity) Nothing <*> areq (selectField optionsFinite) (fslI MsgSystemMessageSeverity) Nothing
<*> areq (langField False) (fslpI MsgSystemMessageLanguage "RFC1766-Sprachcode") (Just $ NonEmpty.head appLanguages) <*> areq (langField False) (fslpI MsgSystemMessageLanguage (mr MsgRFC1766)) (Just $ NonEmpty.head appLanguages)
<*> areq htmlField' (fslpI MsgSystemMessageContent "HTML") Nothing <*> areq htmlField' (fslpI MsgSystemMessageContent "Html") Nothing
<*> aopt htmlField' (fslpI MsgSystemMessageSummary "HTML") Nothing <*> aopt htmlField' (fslpI MsgSystemMessageSummary "Html") Nothing
case addRes of case addRes of
FormMissing -> return () FormMissing -> return ()

View File

@ -8,6 +8,8 @@ import qualified Database.Esqueleto as E
import qualified Data.Set as Set import qualified Data.Set as Set
import qualified Control.Monad.State.Class as State
-- | Default start day of term for season, -- | Default start day of term for season,
-- @True@: start of term, @False@: end of term -- @True@: start of term, @False@: end of term
@ -18,32 +20,15 @@ defaultDay True Summer = fromGregorian 2020 4 1
defaultDay False Summer = fromGregorian 2020 9 30 defaultDay False Summer = fromGregorian 2020 9 30
validateTerm :: Term -> [Text] validateTerm :: (MonadHandler m, HandlerSite m ~ UniWorX)
validateTerm Term{..} = => FormValidator Term m ()
[ msg | (False, msg) <- validateTerm = do
[ --startOk Term{..} <- State.get
( termStart `withinTerm` termName guardValidation MsgTermStartMustMatchName $ termStart `withinTerm` termName
, "Jahreszahl im Namenskürzel stimmt nicht mit Semesterbeginn überein." guardValidation MsgTermEndMustBeAfterStart $ termStart < termEnd
) guardValidation MsgTermLectureEndMustBeAfterStart $ termLectureStart < termLectureEnd
, -- endOk guardValidation MsgTermStartMustBeBeforeLectureStart $ termStart <= termLectureStart
( termStart < termEnd guardValidation MsgTermEndMustBeAfterLectureEnd $ termEnd >= termLectureEnd
, "Semester darf nicht enden, bevor es begann."
)
, -- startOk
( termLectureStart < termLectureEnd
, "Vorlesungszeit muss vor ihrem Ende anfgangen."
)
, -- lecStartOk
( termStart <= termLectureStart
, "Semester muss vor der Vorlesungszeit beginnen."
)
, -- lecEndOk
( termEnd >= termLectureEnd
, "Vorlesungszeit muss vor dem Semester enden."
)
] ]
getTermShowR :: Handler TypedContent getTermShowR :: Handler TypedContent
@ -66,22 +51,22 @@ getTermShowR = do
provideRep $ toJSON . map fst <$> runDB (E.select $ E.from termData) provideRep $ toJSON . map fst <$> runDB (E.select $ E.from termData)
provideRep $ do provideRep $ do
let colonnadeTerms = widgetColonnade $ mconcat let colonnadeTerms = widgetColonnade $ mconcat
[ sortable (Just "term-id") "Kürzel" $ \(Entity tid _, _) -> anchorCell [ sortable (Just "term-id") (i18nCell MsgTermShort) $ \(Entity tid _, _) -> anchorCell
(TermCourseListR tid) (TermCourseListR tid)
[whamlet|#{toPathPiece tid}|] [whamlet|#{toPathPiece tid}|]
, sortable (Just "lecture-start") (i18nCell MsgLectureStart) $ \(Entity _ Term{..},_) -> , sortable (Just "lecture-start") (i18nCell MsgLectureStart) $ \(Entity _ Term{..},_) ->
cell $ formatTime SelFormatDate termLectureStart >>= toWidget cell $ formatTime SelFormatDate termLectureStart >>= toWidget
, sortable (Just "lecture-end") "Ende Vorlesungen" $ \(Entity _ Term{..},_) -> , sortable (Just "lecture-end") (i18nCell MsgTermLectureEnd) $ \(Entity _ Term{..},_) ->
cell $ formatTime SelFormatDate termLectureEnd >>= toWidget cell $ formatTime SelFormatDate termLectureEnd >>= toWidget
, sortable Nothing "Aktiv" $ \(Entity _ Term{..},_) -> , sortable Nothing (i18nCell MsgTermActive) $ \(Entity _ Term{..},_) ->
tickmarkCell termActive tickmarkCell termActive
, sortable Nothing "Kurse" $ \(_, E.Value numCourses) -> , sortable Nothing (i18nCell MsgTermCourseCount) $ \(_, E.Value numCourses) ->
cell [whamlet|_{MsgNumCourses numCourses}|] cell [whamlet|_{MsgNumCourses numCourses}|]
, sortable (Just "start") "Semesteranfang" $ \(Entity _ Term{..},_) -> , sortable (Just "start") (i18nCell MsgTermStart) $ \(Entity _ Term{..},_) ->
cell $ formatTime SelFormatDate termStart >>= toWidget cell $ formatTime SelFormatDate termStart >>= toWidget
, sortable (Just "end") "Semesterende" $ \(Entity _ Term{..},_) -> , sortable (Just "end") (i18nCell MsgTermEnd) $ \(Entity _ Term{..},_) ->
cell $ formatTime SelFormatDate termEnd >>= toWidget cell $ formatTime SelFormatDate termEnd >>= toWidget
, sortable Nothing "Feiertage im Semester" $ \(Entity _ Term{..},_) -> , sortable Nothing (i18nCell MsgTermHolidays) $ \(Entity _ Term{..},_) ->
cell $ do cell $ do
termHolidays' <- mapM (formatTime SelFormatDate) termHolidays termHolidays' <- mapM (formatTime SelFormatDate) termHolidays
[whamlet| [whamlet|
@ -248,7 +233,7 @@ termToTemplate (Just Term{..}) = TermFormTemplate
} }
newTermForm :: TermFormTemplate -> Form Term newTermForm :: TermFormTemplate -> Form Term
newTermForm template html = do newTermForm template = validateForm validateTerm $ \html -> do
mr <- getMessageRender mr <- getMessageRender
let let
tidForm tidForm
@ -264,7 +249,7 @@ newTermForm template html = do
(fslI MsgTermHolidays & setTooltip MsgMassInputTip) (fslI MsgTermHolidays & setTooltip MsgMassInputTip)
True True
(tftHolidays template) (tftHolidays template)
(result, widget) <- flip (renderAForm FormStandard) html $ Term flip (renderAForm FormStandard) html $ Term
<$> tidForm <$> tidForm
<*> areq dayField (fslI MsgTermStartDay & setTooltip MsgTermStartDayTooltip) (tftStart template) <*> areq dayField (fslI MsgTermStartDay & setTooltip MsgTermStartDayTooltip) (tftStart template)
<*> areq dayField (fslI MsgTermEndDay & setTooltip MsgTermEndDayTooltip) (tftEnd template) <*> areq dayField (fslI MsgTermEndDay & setTooltip MsgTermEndDayTooltip) (tftEnd template)
@ -272,24 +257,3 @@ newTermForm template html = do
<*> areq dayField (fslI MsgTermLectureStart) (tftLectureStart template) <*> areq dayField (fslI MsgTermLectureStart) (tftLectureStart template)
<*> areq dayField (fslI MsgTermLectureEnd & setTooltip MsgTermLectureEndTooltip) (tftLectureEnd template) <*> areq dayField (fslI MsgTermLectureEnd & setTooltip MsgTermLectureEndTooltip) (tftLectureEnd template)
<*> areq checkBoxField (fslI MsgTermActive) (tftActive template) <*> areq checkBoxField (fslI MsgTermActive) (tftActive template)
return $ case result of
FormSuccess termResult
| errorMsgs <- validateTerm termResult
, not $ null errorMsgs ->
(FormFailure errorMsgs,
[whamlet|
<div class="alert alert-danger">
<div class="alert__content">
<h4> Fehler:
<ul>
$forall errmsg <- errorMsgs
<li> #{errmsg}
^{widget}
|]
)
_ -> (result, widget)
{-
where
set :: Text -> FieldSettings site
set = bfs
-}

View File

@ -284,21 +284,12 @@ htmlField' = htmlField
natFieldI :: (Monad m, Integral i, RenderMessage (HandlerSite m) msg, RenderMessage (HandlerSite m) FormMessage) => msg -> Field m i natFieldI :: (Monad m, Integral i, RenderMessage (HandlerSite m) msg, RenderMessage (HandlerSite m) FormMessage) => msg -> Field m i
natFieldI msg = convertField fromInteger toInteger $ checkBool (>= 0) msg $ intMinField 0 natFieldI msg = convertField fromInteger toInteger $ checkBool (>= 0) msg $ intMinField 0
natField :: (Monad m, Integral i, RenderMessage (HandlerSite m) FormMessage) => Text -> Field m i
natField d = convertField fromInteger toInteger $ checkBool (>= 0) (T.append d " muss eine natürliche Zahl sein.") $ intMinField 0
natIntField ::(Monad m, RenderMessage (HandlerSite m) FormMessage) => Text -> Field m Integer
natIntField = natField
posIntField :: (Monad m, Integral i, RenderMessage (HandlerSite m) FormMessage) => Text -> Field m i
posIntField d = convertField fromInteger toInteger $ checkBool (> 0) (T.append d " muss eine positive Zahl sein.") $ intMinField 1
posIntFieldI :: (Monad m, Integral i, RenderMessage (HandlerSite m) msg, RenderMessage (HandlerSite m) FormMessage) => msg -> Field m i posIntFieldI :: (Monad m, Integral i, RenderMessage (HandlerSite m) msg, RenderMessage (HandlerSite m) FormMessage) => msg -> Field m i
posIntFieldI msg = convertField fromInteger toInteger $ checkBool (> 0) msg $ intMinField 0 posIntFieldI msg = convertField fromInteger toInteger $ checkBool (> 0) msg $ intMinField 0
-- | Field to request integral number > 'm' -- | Field to request integral number > 'm'
minIntField :: (Monad m, Integral i, Show i, RenderMessage (HandlerSite m) FormMessage) => i -> Text -> Field m i minIntFieldI :: (Monad m, Integral i, Show i, RenderMessage (HandlerSite m) FormMessage, RenderMessage (HandlerSite m) msg) => i -> msg -> Field m i
minIntField m d = checkBool (> m) (T.concat [d," muss größer als ", T.pack $ show m, " sein."]) $ intMinField m minIntFieldI m msg = checkBool (> m) msg $ intMinField m
pointsField :: (Monad m, HandlerSite m ~ UniWorX) => Field m Points pointsField :: (Monad m, HandlerSite m ~ UniWorX) => Field m Points
pointsField = pointsFieldMinMax (Just 0) Nothing pointsField = pointsFieldMinMax (Just 0) Nothing
@ -831,7 +822,7 @@ sheetGroupAFormReq fs template = multiActionA selOptions fs (classify' <$> templ
where where
selOptions = Map.fromList selOptions = Map.fromList
[ ( Arbitrary', Arbitrary [ ( Arbitrary', Arbitrary
<$> apreq (natField "Gruppengröße") (fslI MsgSheetGroupMaxGroupsize & noValidate) (preview _maxParticipants =<< template) <$> apreq (natFieldI MsgGroupSizeNotNatural) (fslI MsgSheetGroupMaxGroupsize & noValidate) (preview _maxParticipants =<< template)
) )
, ( RegisteredGroups', pure RegisteredGroups ) , ( RegisteredGroups', pure RegisteredGroups )
, ( NoGroups', pure NoGroups ) , ( NoGroups', pure NoGroups )
@ -861,6 +852,10 @@ dayTimeField fs mutc = do
| otherwise = (Nothing,Nothing) | otherwise = (Nothing,Nothing)
-} -}
fieldTimeFormat :: String
-- fieldTimeFormat = "%e.%m.%y %k:%M"
fieldTimeFormat = "%Y-%m-%dT%H:%M:%S"
localTimeField :: (MonadHandler m, HandlerSite m ~ UniWorX) => Field m LocalTime localTimeField :: (MonadHandler m, HandlerSite m ~ UniWorX) => Field m LocalTime
localTimeField = Field localTimeField = Field
{ fieldParse = parseHelperGen readTime { fieldParse = parseHelperGen readTime
@ -873,11 +868,7 @@ localTimeField = Field
, fieldEnctype = UrlEncoded , fieldEnctype = UrlEncoded
} }
where where
fieldTimeFormat :: String -- `defaultTimeLocale` is okay here, since `fieldTimeFormat` does not contain any words
--fieldTimeFormat = "%e.%m.%y %k:%M"
fieldTimeFormat = "%Y-%m-%dT%H:%M:%S"
-- `defaultTimeLocale` is okay here, since `fieldTimeFormat` does not contain any
readTime :: Text -> Either UniWorXMessage LocalTime readTime :: Text -> Either UniWorXMessage LocalTime
readTime t = readTime t =
case parseTimeM True defaultTimeLocale fieldTimeFormat (T.unpack t) of case parseTimeM True defaultTimeLocale fieldTimeFormat (T.unpack t) of
@ -1149,7 +1140,7 @@ multiUserField onlySuggested suggestions = Field{..}
case dbRes of case dbRes of
[] -> return $ Left email [] -> return $ Left email
[E.Value uid] -> return $ Right uid [E.Value uid] -> return $ Right uid
_other -> throwE $ SomeMessage ("Ambiguous e-mail addr" :: Text) _other -> throwE $ SomeMessage MsgAmbiguousEmail
examResultField :: forall m res. examResultField :: forall m res.
( MonadHandler m ( MonadHandler m

View File

@ -9,6 +9,11 @@ import Language.Haskell.TH.Syntax (qRunIO)
import qualified Data.List as List import qualified Data.List as List
import qualified Data.List.NonEmpty as NonEmpty import qualified Data.List.NonEmpty as NonEmpty
import qualified Data.Set as Set
import qualified Data.Map as Map
import qualified Data.Text as Text
import System.Directory (listDirectory) import System.Directory (listDirectory)
import System.FilePath.Posix (takeBaseName) import System.FilePath.Posix (takeBaseName)
@ -41,3 +46,23 @@ i18nWidgetFile basename = do
| l <- unpack <$> NonEmpty.toList availableTranslations' -- One function definition for every available language | l <- unpack <$> NonEmpty.toList availableTranslations' -- One function definition for every available language
] ++ [ clause [wildP] (normalB [e| error "selectLanguage returned an invalid translation" |]) [] ] -- Fallback mostly there so compiler does not complain about non-exhaustive pattern match ] ++ [ clause [wildP] (normalB [e| error "selectLanguage returned an invalid translation" |]) [] ] -- Fallback mostly there so compiler does not complain about non-exhaustive pattern match
] [e|selectLanguage availableTranslations' >>= $(varE ws)|] ] [e|selectLanguage availableTranslations' >>= $(varE ws)|]
i18nWidgetFiles :: FilePath -> Q Exp
i18nWidgetFiles basename = do
let i18nDirectory = "templates" </> "i18n" </> basename
availableFiles <- qRunIO $ listDirectory i18nDirectory
let fileKinds' = fmap (pack . dropExtension . takeBaseName &&& toTranslation . pack . takeBaseName) availableFiles
fileKinds :: Map Text [Text]
fileKinds = sortWith (NTop . flip List.elemIndex (NonEmpty.toList appLanguages)) . Set.toList <$> Map.fromListWith Set.union [ (kind, Set.singleton l) | (kind, Just l) <- fileKinds' ]
toTranslation fName = listToMaybe . sortOn length . mapMaybe (flip Text.stripPrefix fName) $ map fst fileKinds'
availableTranslations' <- iforM fileKinds $ \kind -> maybe (fail $ "" <> i18nDirectory <> " has no translations for " <> unpack kind <> "") return . NonEmpty.nonEmpty
-- Dispatch to correct language (depending on user settings via `selectLanguage`) at run time
ws <- newName "ws" -- Name for dispatch function
letE
[ funD ws $ [ clause [litP $ stringL kind, litP $ stringL l] (normalB . widgetFile $ "i18n" </> basename </> kind <.> l) []
| (unpack -> kind, ls) <- Map.toList availableTranslations'
, l <- unpack <$> NonEmpty.toList ls
] ++ [ clause [wildP, wildP] (normalB [e| error "selectLanguage returned an invalid translation" |]) [] ] -- Fallback mostly there so compiler does not complain about non-exhaustive pattern match
] [e|imap (\kind ls -> selectLanguage ls >>= $(varE ws) kind) availableTranslations'|]

View File

@ -0,0 +1,14 @@
.glossary
dt, .dt
font-weight: 600
&.sec
font-style: italic
font-size: 0.9rem
font-weight: 600
color: var(--color-fontsec)
dd, .dd
margin-left: 12px
dd + dt, .dd + dt, dd + .dt, .dd + .dt
margin-top: 17px

View File

@ -0,0 +1,5 @@
$newline never
<dl .glossary>
$forall (term, rTerm, wgt) <- entries'
<dt ##{term}>#{rTerm}
^{wgt}

View File

@ -0,0 +1,8 @@
$newline never
<dt .sec>
Bewerbung
<dt .sec>
Zu einem Kurs bewerben
<dd>
Studierende können eine Bewerbung für einen Kurs hinterlegen.<br />
Wird die Bewerbung akzeptiert (oder der Studierende dem Kurs zugeteilt) wird der Studierende zusätzlich Kursteilnehmer.

View File

@ -0,0 +1,8 @@
$newline never
<dt .sec>
Zu einem Kurs anmelden
<dt .sec>
Von einem Kurs abmelden
<dd>
Studierende, die sich explizit mit einem Kurs assoziiert haben (oder ihm zugeteilt wurden).<br />
Haben Zugriff auf Material und Teile des Kurses (Anmeldungen zu Tutorien, Prüfungen, ...)