diff --git a/routes b/routes index 33692ba6f..50deecf09 100644 --- a/routes +++ b/routes @@ -15,26 +15,17 @@ /course/ CourseListR GET !/course/new CourseNewR GET POST !/course/#TermId CourseListTermR GET +/course/#TermId/#Text CourseR: + /show CourseShowR GET POST + /edit CourseEditR GET POST --- /course/#TermId/#Text CourseR !tag: --- /edit CourseEditR GET POST --- /show CourseShowR GET POST -- CourseR tid csh CourseShowR --- /ex/#Text SheetR: !registered --- /show --- /edit -- CourseR tid csg (SheetR csh SheetEditR) --- /delete - -/course/#TermId/#Text/edit CourseEditR GET -/course/#TermId/#Text/show CourseShowR GET POST - - - -/course/#TermId/#Text/ex/ SheetListR GET -/course/#TermId/#Text/ex/#Text/show SheetShowR GET -/course/#TermId/#Text/ex/#Text/#SheetFileType/#FilePath SheetFileR GET -/course/#TermId/#Text/ex/new SheetNewR GET POST -/course/#TermId/#Text/ex/#Text/edit SheetEditR GET POST -/course/#TermId/#Text/ex/#Text/delete SheetDelR GET POST + /ex SheetR !registered: + / SheetListR GET + /new SheetNewR GET POST !lecturer + /#Text/show SheetShowR GET + /#Text/#SheetFileType/#FilePath SheetFileR GET + /#Text/edit SheetEditR GET POST !lecturer + /#Text/delete SheetDelR GET POST !lecturer /submission SubmissionListR GET POST /submission/#CryptoUUIDSubmission SubmissionR GET POST diff --git a/src/Foundation.hs b/src/Foundation.hs index a3d7d7e4c..474c51c13 100644 --- a/src/Foundation.hs +++ b/src/Foundation.hs @@ -4,6 +4,7 @@ {-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE TypeFamilies #-} {-# LANGUAGE ViewPatterns #-} +{-# LANGUAGE PatternSynonyms #-} {-# LANGUAGE DataKinds #-} {-# LANGUAGE RecordWildCards #-} {-# LANGUAGE NamedFieldPuns #-} @@ -53,6 +54,9 @@ import System.FilePath import Handler.Utils.Templates +-- infixl 9 :$: +-- pattern a :$: b = a b + -- | The foundation datatype for your application. This can be a good place to -- keep settings and values requiring initialization before your application -- starts running, such as database connections. Every handler will have @@ -80,7 +84,9 @@ data UniWorX = UniWorX -- type Widget = WidgetT UniWorX IO () mkYesodData "UniWorX" $(parseRoutesFile "routes") -type DB a = YesodDB UniWorX a +-- Pattern Synonyms for convenience +pattern CSheetR tid csh ptn = CourseR tid csh (SheetR ptn) + data MenuItem = MenuItem { menuItemLabel :: Text @@ -95,7 +101,8 @@ data MenuTypes | NavbarExtra { menuItem :: MenuItem } | NavbarSecondary { menuItem :: MenuItem } --- | A convenient synonym for creating forms. +-- | Convenient Type Synonyms: +type DB a = YesodDB UniWorX a type Form x = Html -> MForm (HandlerT UniWorX IO) (FormResult x, Widget) mkMessage "UniWorX" "messages" "de" @@ -151,7 +158,7 @@ instance Yesod UniWorX where isAuthorized TermShowR _ = return Authorized isAuthorized CourseListR _ = return Authorized isAuthorized (CourseListTermR _) _ = return Authorized - isAuthorized (CourseShowR _ _) _ = return Authorized + isAuthorized (CourseR _ _ CourseShowR) _ = return Authorized isAuthorized (CryptoUUIDDispatchR _) _ = return Authorized isAuthorized SubmissionListR _ = isAuthenticated isAuthorized SubmissionDownloadMultiArchiveR _ = isAuthenticated @@ -205,14 +212,14 @@ isAuthorizedDB (SubmissionDownloadArchiveR (splitExtension -> (baseName, _))) _ isAuthorizedDB TermEditR _ = adminAccess Nothing isAuthorizedDB (TermEditExistR _) _ = adminAccess Nothing isAuthorizedDB CourseNewR _ = lecturerAccess Nothing -isAuthorizedDB (CourseEditR t c) _ = courseLecturerAccess . entityKey =<< getBy404 (CourseTermShort t c) -isAuthorizedDB (SheetListR t c) False = return Authorized -- -isAuthorizedDB (SheetShowR t c s) _ = return Authorized -- TODO: nur für angemeldete Kursteilnehmer falls sichtbar, sonst nur Lectrurer oder Korrektor -isAuthorizedDB (SheetFileR t c s _ _) _ = return Authorized -- TODO: nur für angemeldete Kursteilnehmer falls sichtbar, sonst nur Lectrurer oder Korrektor -isAuthorizedDB (SheetListR t c) _ = courseLecturerAccess . entityKey =<< getBy404 (CourseTermShort t c) -isAuthorizedDB (SheetNewR t c) _ = courseLecturerAccess . entityKey =<< getBy404 (CourseTermShort t c) -isAuthorizedDB (SheetEditR t c s) _ = courseLecturerAccess . entityKey =<< getBy404 (CourseTermShort t c) -isAuthorizedDB (SheetDelR t c s) _ = courseLecturerAccess . entityKey =<< getBy404 (CourseTermShort t c) +isAuthorizedDB (CourseR t c CourseEditR) _ = courseLecturerAccess . entityKey =<< getBy404 (CourseTermShort t c) +isAuthorizedDB (CourseR t c (SheetR SheetListR)) False = return Authorized -- +isAuthorizedDB (CourseR t c (SheetR SheetListR)) _ = courseLecturerAccess . entityKey =<< getBy404 (CourseTermShort t c) +isAuthorizedDB (CourseR t c (SheetR (SheetShowR s))) _ = return Authorized -- TODO: nur für angemeldete Kursteilnehmer falls sichtbar, sonst nur Lectrurer oder Korrektor +isAuthorizedDB (CourseR t c (SheetR (SheetFileR s _ _))) _ = return Authorized -- TODO: nur für angemeldete Kursteilnehmer falls sichtbar, sonst nur Lectrurer oder Korrektor +isAuthorizedDB (CourseR t c (SheetR SheetNewR)) _ = courseLecturerAccess . entityKey =<< getBy404 (CourseTermShort t c) +isAuthorizedDB (CourseR t c (SheetR (SheetEditR s))) _ = courseLecturerAccess . entityKey =<< getBy404 (CourseTermShort t c) +isAuthorizedDB (CourseR t c (SheetR (SheetDelR s))) _ = courseLecturerAccess . entityKey =<< getBy404 (CourseTermShort t c) isAuthorizedDB (CourseEditIDR cID) _ = do courseId <- decrypt cID courseLecturerAccess courseId @@ -285,15 +292,15 @@ instance YesodBreadcrumbs UniWorX where breadcrumb CourseListR = return ("Kurs", Just HomeR) breadcrumb (CourseListTermR term) = return (toPathPiece term, Just TermShowR) - breadcrumb (CourseShowR term course) = return (course, Just $ CourseListTermR term) + breadcrumb (CourseR term course CourseShowR) = return (course, Just $ CourseListTermR term) breadcrumb CourseNewR = return ("Neu", Just CourseListR) - breadcrumb (CourseEditR _ _) = return ("Editieren", Just CourseListR) + breadcrumb (CourseR _ _ CourseEditR) = return ("Editieren", Just CourseListR) - breadcrumb (SheetListR tid csh) = return ("Übungen",Just $ CourseShowR tid csh) - breadcrumb (SheetNewR tid csh) = return ("Neu", Just $ SheetListR tid csh) - breadcrumb (SheetShowR tid csh shn) = return (shn, Just $ SheetListR tid csh) - breadcrumb (SheetEditR tid csh shn) = return ("Edit", Just $ SheetShowR tid csh shn) - breadcrumb (SheetDelR tid csh shn) = return ("DELETE", Just $ SheetShowR tid csh shn) + breadcrumb (CourseR tid csh (SheetR SheetListR)) = return ("Übungen",Just $ CourseR tid csh CourseShowR) + breadcrumb (CourseR tid csh (SheetR SheetNewR )) = return ("Neu", Just $ CourseR tid csh $ SheetR SheetListR) + breadcrumb (CourseR tid csh (SheetR (SheetShowR shn))) = return (shn, Just $ CourseR tid csh $ SheetR SheetListR) + breadcrumb (CourseR tid csh (SheetR (SheetEditR shn))) = return ("Edit", Just $ CourseR tid csh $ SheetR $ SheetShowR shn) + breadcrumb (CourseR tid csh (SheetR (SheetDelR shn))) = return ("DELETE", Just $ CourseR tid csh $ SheetR $ SheetShowR shn) breadcrumb SubmissionListR = return ("Abgaben", Just HomeR) breadcrumb (SubmissionR _) = return ("Abgabe", Just SubmissionListR) diff --git a/src/Handler/Course.hs b/src/Handler/Course.hs index 07597838c..aebfe8634 100644 --- a/src/Handler/Course.hs +++ b/src/Handler/Course.hs @@ -40,7 +40,7 @@ getCourseListTermR tidini = do let c = entityVal ckv shd = courseShorthand c tid = courseTermId c - in [whamlet| #{shd} |] ) + in [whamlet| #{shd} |] ) -- , headed "Institut" $ [shamlet| #{course} |] , headed "Beginn Anmeldung" $ fromString.(maybe "" formatTimeGerWD).courseRegisterFrom.entityVal , headed "Ende Anmeldung" $ fromString.(maybe "" formatTimeGerWD).courseRegisterTo.entityVal @@ -54,11 +54,11 @@ getCourseListTermR tidini = do shd = courseShorthand c tid = courseTermId c in do - adminLink <- handlerToWidget $ isAuthorized (CourseEditR tid shd ) False + adminLink <- handlerToWidget $ isAuthorized (CourseR tid shd CourseEditR) False -- if (adminLink==Authorized) then linkButton "Ändern" BCWarning (CourseEditR tid shd) else "" [whamlet| $if adminLink == Authorized - + editieren |] ) @@ -96,8 +96,8 @@ getCourseShowR tid csh = do [ NavbarAside $ MenuItem { menuItemLabel = "Übungsblätter" , menuItemIcon = Nothing - , menuItemRoute = SheetListR tid csh - , menuItemAccessCallback = (== Authorized) <$> isAuthorized (SheetListR tid csh) False + , menuItemRoute = CSheetR tid csh SheetListR + , menuItemAccessCallback = (== Authorized) <$> isAuthorized (CSheetR tid csh SheetListR) False } ] defaultLinkLayout pageActions $ do @@ -145,6 +145,9 @@ getCourseEditR tid csh = do course <- runDB $ getBy $ CourseTermShort tid csh courseEditHandler course +postCourseEditR :: TermId -> Text -> Handler Html +postCourseEditR = getCourseEditR + getCourseEditIDR :: CryptoUUIDCourse -> Handler Html getCourseEditIDR cID = do cIDKey <- getsYesod appCryptoIDKey @@ -256,7 +259,7 @@ courseEditHandler course = do (FormFailure _) -> addMessageI "warning" MsgInvalidInput other -> addMessage "error" $ [shamlet| Error: #{show other}|] let formTitle = "Kurs editieren/anlegen" :: Text - let actionUrl = CourseNewR -- CourseEditR -- TODO + actionUrl <- fromMaybe CourseNewR <$> getCurrentRoute defaultLayout $ do setTitle [shamlet| #{formTitle} |] $(widgetFile "formPage") diff --git a/src/Handler/Sheet.hs b/src/Handler/Sheet.hs index 77d79eefb..02ab5d510 100644 --- a/src/Handler/Sheet.hs +++ b/src/Handler/Sheet.hs @@ -74,7 +74,7 @@ makeSheetForm template = identForm FIDsheet $ \html -> do <*> areq utcTimeField (fsb "Abgabe ab") (sfActiveFrom <$> template) <*> areq utcTimeField (fsb "Abgabefrist") (sfActiveTo <$> template) <*> fileAFormOpt (fsb "Aufgabenstellung") - <*> aopt utcTimeField (fsb "Hinweis ab") (sfHintFrom <$> template) + <*> aopt utcTimeField (fsb "Hinweise ab") (sfHintFrom <$> template) <*> fileAFormOpt (fsb "Hinweis") <*> aopt utcTimeField (fsb "Lösung ab") (sfSolutionFrom <$> template) <*> fileAFormOpt (fsb "Lösung") @@ -162,7 +162,7 @@ getSheetList courseEnt = do rated <- count $ (SubmissionRatingTime !=. Nothing):sheetsub return (sid, sheet, (submissions, rated)) let colBase = mconcat - [ headed "Blatt" $ \(sid,sheet,_) -> linkButton (toWgt $ sheetName sheet) BCLink $ SheetShowR tid csh (sheetName sheet) + [ headed "Blatt" $ \(sid,sheet,_) -> linkButton (toWgt $ sheetName sheet) BCLink $ CourseR tid csh $ SheetR $ SheetShowR $ sheetName sheet , headed "Abgabe ab" $ toWgt . formatTimeGerWD . sheetActiveFrom . snd3 , headed "Abgabe bis" $ toWgt . formatTimeGerWD . sheetActiveTo . snd3 , headed "Bewertung" $ toWgt . show . sheetType . snd3 @@ -170,13 +170,13 @@ getSheetList courseEnt = do , headed "Eingereicht" $ toWgt . fst . trd3 ] let colAdmin = mconcat -- only show edit button for allowed course assistants - [ headed "" $ \s -> linkButton "Edit" BCLink $ SheetEditR tid csh $ sheetName $ snd3 s - , headed "" $ \s -> linkButton "Delete" BCLink $ SheetDelR tid csh $ sheetName $ snd3 s + [ headed "" $ \s -> linkButton "Edit" BCLink $ CourseR tid csh $ SheetR $ SheetEditR $ sheetName $ snd3 s + , headed "" $ \s -> linkButton "Delete" BCLink $ CourseR tid csh $ SheetR $ SheetDelR $ sheetName $ snd3 s ] showAdmin <- case sheets of ((_,firstSheet,_):_) -> do setUltDestCurrent - (Authorized ==) <$> isAuthorized (SheetEditR tid csh $ sheetName firstSheet) False + (Authorized ==) <$> isAuthorized (CourseR tid csh $ SheetR $ SheetEditR $ sheetName firstSheet) False _otherwise -> return False let colSheets = if showAdmin then colBase `mappend` colAdmin @@ -185,7 +185,7 @@ getSheetList courseEnt = do [ NavbarAside $ MenuItem { menuItemLabel = "Neues Übungsblatt" , menuItemIcon = Nothing - , menuItemRoute = SheetNewR tid csh + , menuItemRoute = CSheetR tid csh SheetNewR , menuItemAccessCallback = (== Authorized) <$> isAuthorized CourseNewR False } ] @@ -211,7 +211,7 @@ getSheetShowR tid csh shn = do E.where_ (sheet E.^. SheetId E.==. E.val sid ) -- return desired columns return $ (file E.^. FileTitle, sheetFile E.^. SheetFileType) - let fileLinks = map (\(E.Value fName, E.Value fType) -> SheetFileR tid csh shn fType fName) fileNameTypes + let fileLinks = map (\(E.Value fName, E.Value fType) -> CSheetR tid csh (SheetFileR shn fType fName)) fileNameTypes defaultLayout $ do setTitle $ toHtml $ T.append "Übung " $ sheetName sheet @@ -325,14 +325,14 @@ handleSheetEdit tid csh template dbAction = do whenIsJust sfSolutionF $ insertSheetFile sid SheetSolution addMessageI "info" $ MsgSheetEditOk tident csh sfName return True - when saveOkay $ redirect $ SheetShowR tid csh sfName -- redirect must happen outside of runDB + when saveOkay $ redirect $ CSheetR tid csh $ SheetShowR sfName -- redirect must happen outside of runDB (FormFailure msgs) -> forM_ msgs $ (addMessage "warning") . toHtml _ -> return () let pageTitle = maybe (MsgSheetTitleNew tident csh) (MsgSheetTitle tident csh) mbshn let formTitle = pageTitle let formText = Nothing :: Maybe UniWorXMessage - actionUrl <- fromMaybe (SheetNewR tid csh) <$> getCurrentRoute + actionUrl <- fromMaybe (CSheetR tid csh SheetNewR) <$> getCurrentRoute defaultLayout $ do setTitleI pageTitle $(widgetFile "formPageI18n") @@ -344,19 +344,19 @@ getSheetDelR tid csh shn = do let tident = unTermKey tid ((result,formWidget), formEnctype) <- runFormPost (buttonForm :: Form BtnDelete) case result of - (FormSuccess BtnAbort) -> redirectUltDest $ SheetShowR tid csh shn + (FormSuccess BtnAbort) -> redirectUltDest $ CSheetR tid csh $ SheetShowR shn (FormSuccess BtnDelete) -> do runDB $ fetchSheetId tid csh shn >>= deleteCascade -- TODO: deleteCascade löscht aber nicht die hochgeladenen Dateien!!! setMessageI $ MsgSheetDelOk tident csh shn - redirect $ SheetListR tid csh + redirect $ CSheetR tid csh SheetListR _other -> do submissionno <- runDB $ do sid <- fetchSheetId tid csh shn count [SubmissionSheetId ==. sid] let formTitle = MsgSheetDelTitle tident csh shn let formText = Just $ MsgSheetDelText submissionno - let actionUrl = SheetDelR tid csh shn + let actionUrl = CSheetR tid csh $ SheetDelR shn defaultLayout $ do setTitleI $ MsgSheetTitle tident csh shn $(widgetFile "formPageI18n") diff --git a/src/Handler/Submission.hs b/src/Handler/Submission.hs index 3fb482691..78ec0ed4a 100644 --- a/src/Handler/Submission.hs +++ b/src/Handler/Submission.hs @@ -53,7 +53,7 @@ submissionTable = do (,,) <$> encrypt submissionId <*> encrypt submissionId <*> pure s let - anchorCourse (_, _, (_, _, Entity _ Course{..})) = CourseShowR courseTermId courseShorthand + anchorCourse (_, _, (_, _, Entity _ Course{..})) = CourseR courseTermId courseShorthand CourseShowR courseText (_, _, (_, _, Entity _ Course{..})) = toWidget courseName anchorSubmission (_, cUUID, _) = SubmissionR cUUID submissionText (cID, _, _) = toWidget . toPathPiece . CI.foldedCase $ ciphertext cID diff --git a/src/Model/Types.hs b/src/Model/Types.hs index 7201671ab..321df30b8 100644 --- a/src/Model/Types.hs +++ b/src/Model/Types.hs @@ -55,7 +55,7 @@ deriveJSON defaultOptions ''SheetType derivePersistFieldJSON "SheetType" data SheetGroup - = Arbitrary { maxParticipants :: Int } + = Arbitrary { maxParticipants :: Int } -- Distinguish Limited/Arbitrary | RegisteredGroups | NoGroups deriving (Show, Read, Eq) diff --git a/templates/course.hamlet b/templates/course.hamlet index 14e8f6ad2..94d8dbfb4 100644 --- a/templates/course.hamlet +++ b/templates/course.hamlet @@ -16,7 +16,7 @@ \ bis #{formatTimeGerWD regTo}
-
+ ^{regWidget}
diff --git a/templates/sheetShow.hamlet b/templates/sheetShow.hamlet index ddcb31600..0d2f4090d 100644 --- a/templates/sheetShow.hamlet +++ b/templates/sheetShow.hamlet @@ -29,7 +29,7 @@ $forall fileLink <- fileLinks
  • $case fileLink - $of SheetFileR _ _ _ typ name + $of CourseR _ _ (SheetR (SheetFileR _ typ name)) #{toPathPiece typ} #{name} $of other