Merge branch 'master' into 284-massinput

This commit is contained in:
Gregor Kleen 2019-01-31 11:13:27 +01:00
commit 7acba967d1
18 changed files with 252 additions and 242 deletions

View File

@ -7,6 +7,7 @@ BtnHijack: Sitzung übernehmen
Aborted: Abgebrochen Aborted: Abgebrochen
Registered: Angemeldet Registered: Angemeldet
RegisteredSince date@Text: Angemeldet seit #{date}
RegisterFrom: Anmeldungen von RegisterFrom: Anmeldungen von
RegisterTo: Anmeldungen bis RegisterTo: Anmeldungen bis
DeRegUntil: Abmeldungen bis DeRegUntil: Abmeldungen bis
@ -108,7 +109,7 @@ SheetSolutionFrom: Lösung ab
SheetMarking: Hinweise für Korrektoren SheetMarking: Hinweise für Korrektoren
SheetType: Wertung SheetType: Wertung
SheetInvisible: Dieses Übungsblatt ist für Teilnehmer momentan unsichtbar! SheetInvisible: Dieses Übungsblatt ist für Teilnehmer momentan unsichtbar!
SheetInvisibleUntil mFrom@Text: Dieses Übungsblatt ist für Teilnehmer momentan unsichtbar bis #{mFrom}! SheetInvisibleUntil date@Text: Dieses Übungsblatt ist für Teilnehmer momentan unsichtbar bis #{date}!
SheetName: Name SheetName: Name
SheetDescription: Hinweise für Teilnehmer SheetDescription: Hinweise für Teilnehmer
SheetGroup: Gruppenabgabe SheetGroup: Gruppenabgabe
@ -570,13 +571,14 @@ MenuSheetNew: Neues Übungsblatt anlegen
MenuSheetCurrent: Aktuelles Übungsblatt MenuSheetCurrent: Aktuelles Übungsblatt
MenuSheetOldUnassigned: Abgaben ohne Korrektor MenuSheetOldUnassigned: Abgaben ohne Korrektor
MenuCourseEdit: Kurs editieren MenuCourseEdit: Kurs editieren
MenuCourseNewTemplate: Als neuen Kurs klonen MenuCourseClone: Als neuen Kurs klonen
MenuCourseDelete: Kurs löschen MenuCourseDelete: Kurs löschen
MenuSubmissionNew: Abgabe anlegen MenuSubmissionNew: Abgabe anlegen
MenuSubmissionOwn: Abgabe MenuSubmissionOwn: Abgabe
MenuCorrectors: Korrektoren MenuCorrectors: Korrektoren
MenuSheetEdit: Übungsblatt editieren MenuSheetEdit: Übungsblatt editieren
MenuSheetDelete: Übungsblatt löschen MenuSheetDelete: Übungsblatt löschen
MenuSheetClone: Als neues Übungsblatt klonen
MenuCorrectionsUpload: Korrekturen hochladen MenuCorrectionsUpload: Korrekturen hochladen
MenuCorrectionsCreate: Abgaben registrieren MenuCorrectionsCreate: Abgaben registrieren
MenuCorrectionsGrade: Abgaben bewerten MenuCorrectionsGrade: Abgaben bewerten

6
routes
View File

@ -72,9 +72,9 @@
/notes CNotesR GET POST !corrector /notes CNotesR GET POST !corrector
/subs CCorrectionsR GET POST /subs CCorrectionsR GET POST
/ex SheetListR GET !registered !materials !corrector /ex SheetListR GET !registered !materials !corrector
!/ex/new SheetNewR GET POST /ex/new SheetNewR GET POST
!/ex/current SheetCurrentR GET !free -- just a redirect /ex/current SheetCurrentR GET !registered !materials !corrector
!/ex/lastinactive SheetOldUnassigned GET !free -- just a redirect /ex/unassigned SheetOldUnassigned GET
/ex/#SheetName SheetR: /ex/#SheetName SheetR:
/show SShowR GET !timeANDregistered !timeANDmaterials !corrector /show SShowR GET !timeANDregistered !timeANDmaterials !corrector
/edit SEditR GET POST /edit SEditR GET POST

View File

@ -14,15 +14,14 @@ import qualified Data.CaseInsensitive as CI
data DummyMessage = MsgDummyIdent data DummyMessage = MsgDummyIdent
| MsgDummyNoFormData | MsgDummyNoFormData
deriving (Eq, Ord, Enum, Bounded, Read, Show, Generic, Typeable)
dummyForm :: ( RenderMessage site FormMessage dummyForm :: ( RenderMessage site FormMessage
, RenderMessage site DummyMessage , RenderMessage site DummyMessage
, RenderMessage site ButtonMessage
, YesodPersist site , YesodPersist site
, SqlBackendCanRead (YesodPersistBackend site) , SqlBackendCanRead (YesodPersistBackend site)
, Button site SubmitButton , Button site ButtonSubmit
, Show (ButtonCssClass site)
) => AForm (HandlerT site IO) (CI Text) ) => AForm (HandlerT site IO) (CI Text)
dummyForm = areq (selectField userList) (fslI MsgDummyIdent) Nothing dummyForm = areq (selectField userList) (fslI MsgDummyIdent) Nothing
<* submitButton <* submitButton
@ -35,9 +34,7 @@ dummyLogin :: ( YesodAuth site
, SqlBackendCanRead (YesodPersistBackend site) , SqlBackendCanRead (YesodPersistBackend site)
, RenderMessage site FormMessage , RenderMessage site FormMessage
, RenderMessage site DummyMessage , RenderMessage site DummyMessage
, RenderMessage site ButtonMessage , Button site ButtonSubmit
, Button site SubmitButton
, Show (ButtonCssClass site)
) => AuthPlugin site ) => AuthPlugin site
dummyLogin = AuthPlugin{..} dummyLogin = AuthPlugin{..}
where where

View File

@ -28,13 +28,14 @@ import qualified Yesod.Auth.Message as Msg
data CampusLogin = CampusLogin data CampusLogin = CampusLogin
{ campusIdent :: CI Text { campusIdent :: CI Text
, campusPassword :: Text , campusPassword :: Text
} } deriving (Generic, Typeable)
data CampusMessage = MsgCampusIdentNote data CampusMessage = MsgCampusIdentNote
| MsgCampusIdent | MsgCampusIdent
| MsgCampusPassword | MsgCampusPassword
| MsgCampusSubmit | MsgCampusSubmit
| MsgCampusInvalidCredentials | MsgCampusInvalidCredentials
deriving (Eq, Ord, Enum, Bounded, Read, Show, Generic, Typeable)
findUser :: LdapConf -> Ldap -> Text -> [Ldap.Attr] -> IO [Ldap.SearchEntry] findUser :: LdapConf -> Ldap -> Text -> [Ldap.Attr] -> IO [Ldap.SearchEntry]
@ -53,9 +54,7 @@ userPrincipalName = Ldap.Attr "userPrincipalName"
campusForm :: ( RenderMessage site FormMessage campusForm :: ( RenderMessage site FormMessage
, RenderMessage site CampusMessage , RenderMessage site CampusMessage
, RenderMessage site ButtonMessage , Button site ButtonSubmit
, Button site SubmitButton
, Show (ButtonCssClass site)
) => AForm (HandlerT site IO) CampusLogin ) => AForm (HandlerT site IO) CampusLogin
campusForm = CampusLogin campusForm = CampusLogin
<$> areq ciField (fslpI MsgCampusIdent "user.name@campus.lmu.de" & setTooltip MsgCampusIdentNote) Nothing <$> areq ciField (fslpI MsgCampusIdent "user.name@campus.lmu.de" & setTooltip MsgCampusIdentNote) Nothing
@ -66,9 +65,7 @@ campusLogin :: forall site.
( YesodAuth site ( YesodAuth site
, RenderMessage site FormMessage , RenderMessage site FormMessage
, RenderMessage site CampusMessage , RenderMessage site CampusMessage
, RenderMessage site ButtonMessage , Button site ButtonSubmit
, Button site SubmitButton
, Show (ButtonCssClass site)
) => LdapConf -> LdapPool -> AuthPlugin site ) => LdapConf -> LdapPool -> AuthPlugin site
campusLogin conf@LdapConf{..} pool = AuthPlugin{..} campusLogin conf@LdapConf{..} pool = AuthPlugin{..}
where where
@ -116,7 +113,7 @@ data CampusUserException = CampusUserLdapError LdapPoolError
| CampusUserHostCannotConnect String [IOException] | CampusUserHostCannotConnect String [IOException]
| CampusUserNoResult | CampusUserNoResult
| CampusUserAmbiguous | CampusUserAmbiguous
deriving (Show, Eq, Typeable) deriving (Show, Eq, Generic, Typeable)
instance Exception CampusUserException instance Exception CampusUserException

View File

@ -19,17 +19,16 @@ import qualified Yesod.Auth.Message as Msg
data HashLogin = HashLogin data HashLogin = HashLogin
{ hashIdent :: CI Text { hashIdent :: CI Text
, hashPassword :: Text , hashPassword :: Text
} } deriving (Generic, Typeable)
data PWHashMessage = MsgPWHashIdent data PWHashMessage = MsgPWHashIdent
| MsgPWHashPassword | MsgPWHashPassword
deriving (Eq, Ord, Enum, Bounded, Read, Show, Generic, Typeable)
hashForm :: ( RenderMessage site FormMessage hashForm :: ( RenderMessage site FormMessage
, RenderMessage site PWHashMessage , RenderMessage site PWHashMessage
, RenderMessage site ButtonMessage , Button site ButtonSubmit
, Button site SubmitButton
, Show (ButtonCssClass site)
) => AForm (HandlerT site IO) HashLogin ) => AForm (HandlerT site IO) HashLogin
hashForm = HashLogin hashForm = HashLogin
<$> areq ciField (fslpI MsgPWHashIdent "Identifikation") Nothing <$> areq ciField (fslpI MsgPWHashIdent "Identifikation") Nothing
@ -42,9 +41,7 @@ hashLogin :: ( YesodAuth site
, SqlBackendCanRead (YesodPersistBackend site) , SqlBackendCanRead (YesodPersistBackend site)
, RenderMessage site FormMessage , RenderMessage site FormMessage
, RenderMessage site PWHashMessage , RenderMessage site PWHashMessage
, RenderMessage site ButtonMessage , Button site ButtonSubmit
, Button site SubmitButton
, Show (ButtonCssClass site)
) => PWHashAlgorithm -> AuthPlugin site ) => PWHashAlgorithm -> AuthPlugin site
hashLogin pwHashAlgo = AuthPlugin{..} hashLogin pwHashAlgo = AuthPlugin{..}
where where

View File

@ -276,13 +276,28 @@ menuItemAccessCallback MenuItem{..} = and2M ((==) Authorized <$> authCheck) menu
$(return []) $(return [])
data instance ButtonCssClass UniWorX = BCDefault | BCPrimary | BCSuccess | BCInfo | BCWarning | BCDanger | BCLink data instance ButtonClass UniWorX
deriving (Enum, Eq, Ord, Bounded, Read, Show) = BCIsButton
| BCDefault
| BCPrimary
| BCSuccess
| BCInfo
| BCWarning
| BCDanger
| BCLink
deriving (Enum, Eq, Ord, Bounded, Read, Show, Generic, Typeable)
instance Universe (ButtonClass UniWorX)
instance Finite (ButtonClass UniWorX)
instance Button UniWorX SubmitButton where instance PathPiece (ButtonClass UniWorX) where
label BtnSubmit = [whamlet|_{MsgBtnSubmit}|] toPathPiece BCIsButton = "btn"
toPathPiece bClass = ("btn-" <>) . camelToPathPiece' 1 $ tshow bClass
fromPathPiece = finiteFromPathPiece
cssClass BtnSubmit = BCPrimary
embedRenderMessage ''UniWorX ''ButtonSubmit id
instance Button UniWorX ButtonSubmit where
btnClasses BtnSubmit = [BCIsButton, BCPrimary]
getTimeLocale' :: [Lang] -> TimeLocale getTimeLocale' :: [Lang] -> TimeLocale
@ -463,12 +478,22 @@ tagAccessPredicate AuthTime = APDB $ \route _ -> case route of
return Authorized return Authorized
CourseR tid ssh csh CRegisterR -> maybeT (unauthorizedI MsgUnauthorizedCourseTime) $ do CourseR tid ssh csh CRegisterR -> do
Entity _ Course{courseRegisterFrom, courseRegisterTo} <- MaybeT . getBy $ TermSchoolCourseShort tid ssh csh mbc <- getBy $ TermSchoolCourseShort tid ssh csh
mAid <- lift maybeAuthId
registered <- case (mbc,mAid) of
(Just (Entity cid _), Just uid) -> isJust <$> (getBy $ UniqueParticipant uid cid)
_ -> return False
cTime <- (NTop . Just) <$> liftIO getCurrentTime cTime <- (NTop . Just) <$> liftIO getCurrentTime
guard $ NTop courseRegisterFrom <= cTime case mbc of
&& NTop courseRegisterTo >= cTime (Just (Entity _ Course{courseRegisterFrom, courseRegisterTo}))
return Authorized | not registered
, courseRegisterFrom <= nBot cTime
, NTop courseRegisterTo >= cTime -> return Authorized
(Just (Entity _ Course{courseDeregisterUntil}))
| registered
, NTop courseDeregisterUntil >= cTime -> return Authorized
_other -> unauthorizedI MsgUnauthorizedCourseTime
MessageR cID -> maybeT (unauthorizedI MsgUnauthorizedSystemMessageTime) $ do MessageR cID -> maybeT (unauthorizedI MsgUnauthorizedSystemMessageTime) $ do
smId <- decrypt cID smId <- decrypt cID
@ -1265,8 +1290,8 @@ pageActions (CourseR tid ssh csh CShowR) =
} }
, MenuItem , MenuItem
{ menuItemType = PageActionSecondary { menuItemType = PageActionSecondary
, menuItemLabel = MsgMenuCourseNewTemplate , menuItemLabel = MsgMenuCourseClone
, menuItemIcon = Nothing , menuItemIcon = Just "copy"
, menuItemRoute = SomeRoute (CourseNewR, [("tid", toPathPiece tid), ("ssh", toPathPiece ssh), ("csh", toPathPiece csh)]) , menuItemRoute = SomeRoute (CourseNewR, [("tid", toPathPiece tid), ("ssh", toPathPiece ssh), ("csh", toPathPiece csh)])
, menuItemModal = False , menuItemModal = False
, menuItemAccessCallback' = return True , menuItemAccessCallback' = return True
@ -1274,7 +1299,7 @@ pageActions (CourseR tid ssh csh CShowR) =
, MenuItem , MenuItem
{ menuItemType = PageActionSecondary { menuItemType = PageActionSecondary
, menuItemLabel = MsgMenuCourseDelete , menuItemLabel = MsgMenuCourseDelete
, menuItemIcon = Nothing , menuItemIcon = Just "trash"
, menuItemRoute = SomeRoute $ CourseR tid ssh csh CDeleteR , menuItemRoute = SomeRoute $ CourseR tid ssh csh CDeleteR
, menuItemModal = False , menuItemModal = False
, menuItemAccessCallback' = return True , menuItemAccessCallback' = return True
@ -1287,21 +1312,9 @@ pageActions (CourseR tid ssh csh SheetListR) =
, menuItemIcon = Nothing , menuItemIcon = Nothing
, menuItemRoute = SomeRoute $ CourseR tid ssh csh SheetCurrentR , menuItemRoute = SomeRoute $ CourseR tid ssh csh SheetCurrentR
, menuItemModal = False , menuItemModal = False
, menuItemAccessCallback' = do , menuItemAccessCallback' = runDB . maybeT (return False) $ do
now <- liftIO getCurrentTime void . MaybeT $ sheetCurrent tid ssh csh
sheets <- runDB . E.select . E.from $ \(course `E.InnerJoin` sheet) -> do return True
E.on $ sheet E.^. SheetCourse E.==. course E.^. CourseId
E.where_ $ sheet E.^. SheetActiveTo E.>. E.val now
E.&&. sheet E.^. SheetActiveFrom E.<=. E.val now
E.&&. course E.^. CourseTerm E.==. E.val tid
E.&&. course E.^. CourseSchool E.==. E.val ssh
E.&&. course E.^. CourseShorthand E.==. E.val csh
E.orderBy [E.asc $ sheet E.^. SheetActiveTo]
E.limit 1
return $ sheet E.^. SheetName
case sheets of
(E.Value shn):_ -> (== Authorized) <$> isAuthorized (CSheetR tid ssh csh shn SShowR) False
_ -> return False
} }
, MenuItem , MenuItem
{ menuItemType = PageActionPrime { menuItemType = PageActionPrime
@ -1310,7 +1323,6 @@ pageActions (CourseR tid ssh csh SheetListR) =
, menuItemRoute = SomeRoute $ CourseR tid ssh csh SheetOldUnassigned , menuItemRoute = SomeRoute $ CourseR tid ssh csh SheetOldUnassigned
, menuItemModal = False , menuItemModal = False
, menuItemAccessCallback' = runDB . maybeT (return False) $ do , menuItemAccessCallback' = runDB . maybeT (return False) $ do
guardM $ (== Authorized) <$> evalAccessCorrector tid ssh csh
void . MaybeT $ sheetOldUnassigned tid ssh csh void . MaybeT $ sheetOldUnassigned tid ssh csh
return True return True
} }
@ -1367,18 +1379,6 @@ pageActions (CSheetR tid ssh csh shn SShowR) =
guard $ null submissions guard $ null submissions
return True return True
} }
, MenuItem
{ menuItemType = PageActionPrime
, menuItemLabel = MsgMenuCorrectionsOwn
, menuItemIcon = Nothing
, menuItemRoute = SomeRoute (CorrectionsR, [ ("corrections-term" , termToText $ unTermKey tid)
, ("corrections-school", CI.original $ unSchoolKey ssh)
, ("corrections-course", CI.original csh)
, ("corrections-sheet" , CI.original shn)
])
, menuItemModal = False
, menuItemAccessCallback' = (== Authorized) <$> evalAccessCorrector tid ssh csh
}
, MenuItem , MenuItem
{ menuItemType = PageActionPrime { menuItemType = PageActionPrime
, menuItemLabel = MsgMenuSubmissionOwn , menuItemLabel = MsgMenuSubmissionOwn
@ -1391,6 +1391,18 @@ pageActions (CSheetR tid ssh csh shn SShowR) =
guard . not $ null submissions guard . not $ null submissions
return True return True
} }
, MenuItem
{ menuItemType = PageActionPrime
, menuItemLabel = MsgMenuCorrectionsOwn
, menuItemIcon = Nothing
, menuItemRoute = SomeRoute (CorrectionsR, [ ("corrections-term" , termToText $ unTermKey tid)
, ("corrections-school", CI.original $ unSchoolKey ssh)
, ("corrections-course", CI.original csh)
, ("corrections-sheet" , CI.original shn)
])
, menuItemModal = False
, menuItemAccessCallback' = (== Authorized) <$> evalAccessCorrector tid ssh csh
}
, MenuItem , MenuItem
{ menuItemType = PageActionPrime { menuItemType = PageActionPrime
, menuItemLabel = MsgMenuCorrectors , menuItemLabel = MsgMenuCorrectors
@ -1415,10 +1427,18 @@ pageActions (CSheetR tid ssh csh shn SShowR) =
, menuItemModal = False , menuItemModal = False
, menuItemAccessCallback' = return True , menuItemAccessCallback' = return True
} }
, MenuItem
{ menuItemType = PageActionSecondary
, menuItemLabel = MsgMenuSheetClone
, menuItemIcon = Just "copy"
, menuItemRoute = SomeRoute (CourseR tid ssh csh SheetNewR, [("shn", toPathPiece shn)])
, menuItemModal = False
, menuItemAccessCallback' = return True
}
, MenuItem , MenuItem
{ menuItemType = PageActionSecondary { menuItemType = PageActionSecondary
, menuItemLabel = MsgMenuSheetDelete , menuItemLabel = MsgMenuSheetDelete
, menuItemIcon = Nothing , menuItemIcon = Just "trash"
, menuItemRoute = SomeRoute $ CSheetR tid ssh csh shn SDelR , menuItemRoute = SomeRoute $ CSheetR tid ssh csh shn SDelR
, menuItemModal = False , menuItemModal = False
, menuItemAccessCallback' = return True , menuItemAccessCallback' = return True

View File

@ -13,8 +13,6 @@ import Control.Monad.Trans.Except
-- import Data.Function ((&)) -- import Data.Function ((&))
-- import Yesod.Form.Bootstrap3 -- import Yesod.Form.Bootstrap3
import Web.PathPieces (showToPathPiece, readFromPathPiece)
import Database.Persist.Sql (fromSqlKey) import Database.Persist.Sql (fromSqlKey)
-- import Colonnade hiding (fromMaybe) -- import Colonnade hiding (fromMaybe)
@ -23,19 +21,19 @@ import Database.Persist.Sql (fromSqlKey)
-- import qualified Data.UUID.Cryptographic as UUID -- import qualified Data.UUID.Cryptographic as UUID
-- BEGIN - Buttons needed only here -- BEGIN - Buttons needed only here
data CreateButton = CreateMath | CreateInf -- Dummy for Example data ButtonCreate = CreateMath | CreateInf -- Dummy for Example
deriving (Enum, Eq, Ord, Bounded, Read, Show) deriving (Enum, Eq, Ord, Bounded, Read, Show, Generic, Typeable)
instance Universe ButtonCreate
instance Finite ButtonCreate
instance PathPiece CreateButton where -- for displaying the button only, not really for paths nullaryPathPiece ''ButtonCreate camelToPathPiece
toPathPiece = showToPathPiece
fromPathPiece = readFromPathPiece
instance Button UniWorX CreateButton where instance Button UniWorX ButtonCreate where
label CreateMath = [whamlet|Ma<i>thema</i>tik|] btnLabel CreateMath = [whamlet|Ma<i>thema</i>tik|]
label CreateInf = "Informatik" btnLabel CreateInf = "Informatik"
cssClass CreateMath = BCInfo btnClasses CreateMath = [BCIsButton, BCInfo]
cssClass CreateInf = BCPrimary btnClasses CreateInf = [BCIsButton, BCPrimary]
-- END Button needed here -- END Button needed here
emailTestForm :: AForm (HandlerT UniWorX IO) (Email, MailContext) emailTestForm :: AForm (HandlerT UniWorX IO) (Email, MailContext)
@ -60,7 +58,7 @@ emailTestForm = (,)
getAdminTestR, postAdminTestR :: Handler Html -- Demo Page. Referenzimplementierungen sollte hier gezeigt werden! getAdminTestR, postAdminTestR :: Handler Html -- Demo Page. Referenzimplementierungen sollte hier gezeigt werden!
getAdminTestR = postAdminTestR getAdminTestR = postAdminTestR
postAdminTestR = do postAdminTestR = do
((btnResult, btnWdgt), btnEnctype) <- runFormPost $ identifyForm "buttons" (buttonForm :: Form CreateButton) ((btnResult, btnWdgt), btnEnctype) <- runFormPost $ identifyForm "buttons" (buttonForm :: Form ButtonCreate)
case btnResult of case btnResult of
(FormSuccess CreateInf) -> addMessage Info "Informatik-Knopf gedrückt" (FormSuccess CreateInf) -> addMessage Info "Informatik-Knopf gedrückt"
(FormSuccess CreateMath) -> addMessage Warning "Knopf Mathematik erkannt" (FormSuccess CreateMath) -> addMessage Warning "Knopf Mathematik erkannt"

View File

@ -259,25 +259,31 @@ getTermCourseListR tid = do
getCShowR :: TermId -> SchoolId -> CourseShorthand -> Handler Html getCShowR :: TermId -> SchoolId -> CourseShorthand -> Handler Html
getCShowR tid ssh csh = do getCShowR tid ssh csh = do
mbAid <- maybeAuthId mbAid <- maybeAuthId
(courseEnt,(schoolMB,participants,registered),lecturers) <- runDB $ do (course,schoolName,participants,registered,lecturers) <- runDB . maybeT notFound $ do
courseEnt@(Entity cid course) <- getBy404 $ TermSchoolCourseShort tid ssh csh [(E.Entity cid course, E.Value schoolName, E.Value participants, E.Value registered)]
dependent <- (,,) <- lift . E.select . E.from $
<$> get (courseSchool course) -- join -- just fetch full school name here \((school `E.InnerJoin` course) `E.LeftOuterJoin` participant) -> do
<*> count [CourseParticipantCourse ==. cid] -- join E.on $ E.just (course E.^. CourseId) E.==. participant E.?. CourseParticipantCourse
<*> (case mbAid of -- TODO: Someone please refactor this late-night mess here! E.&&. E.val mbAid E.==. participant E.?. CourseParticipantUser
Nothing -> return False E.on $ course E.^. CourseSchool E.==. school E.^. SchoolId
(Just aid) -> do regL <- getBy (UniqueParticipant aid cid) E.where_ $ course E.^. CourseTerm E.==. E.val tid
return $ isJust regL) E.&&. course E.^. CourseSchool E.==. E.val ssh
lecturers <- E.select $ E.from $ \(lecturer `E.InnerJoin` user) -> do E.&&. course E.^. CourseShorthand E.==. E.val csh
E.on $ lecturer E.^. LecturerUser E.==. user E.^. UserId let numParticipants = E.sub_select . E.from $ \part -> do
E.where_ $ lecturer E.^. LecturerCourse E.==. E.val cid E.where_ $ part E.^. CourseParticipantCourse E.==. course E.^. CourseId
return $ user E.^. UserDisplayName return ( E.countRows :: E.SqlExpr (E.Value Int64))
return (courseEnt,dependent,E.unValue <$> lecturers) return (course,school E.^. SchoolName, numParticipants, participant E.?. CourseParticipantRegistration)
let course = entityVal courseEnt lecturers <- lift . E.select $ E.from $ \(lecturer `E.InnerJoin` user) -> do
(regWidget, regEnctype) <- generateFormPost $ identifyForm "registerBtn" $ registerForm registered $ courseRegisterSecret course E.on $ lecturer E.^. LecturerUser E.==. user E.^. UserId
E.where_ $ lecturer E.^. LecturerCourse E.==. E.val cid
return $ user E.^. UserDisplayName
return (course,schoolName,participants,registered,map E.unValue lecturers)
mRegFrom <- traverse (formatTime SelFormatDateTime) $ courseRegisterFrom course
mRegTo <- traverse (formatTime SelFormatDateTime) $ courseRegisterTo course
mDereg <- traverse (formatTime SelFormatDateTime) $ courseDeregisterUntil course
mRegAt <- traverse (formatTime SelFormatDateTime) registered
(regWidget, regEnctype) <- generateFormPost $ identifyForm "registerBtn" $ registerForm (isJust mRegAt) $ courseRegisterSecret course
registrationOpen <- (==Authorized) <$> isAuthorized (CourseR tid ssh csh CRegisterR) True registrationOpen <- (==Authorized) <$> isAuthorized (CourseR tid ssh csh CRegisterR) True
mRegFrom <- traverse (formatTime SelFormatDateTime) $ courseRegisterFrom course
mRegTo <- traverse (formatTime SelFormatDateTime) $ courseRegisterTo course
defaultLayout $ do defaultLayout $ do
setTitle [shamlet| #{toPathPiece tid} - #{csh}|] setTitle [shamlet| #{toPathPiece tid} - #{csh}|]
$(widgetFile "course") $(widgetFile "course")

View File

@ -222,7 +222,7 @@ getProfileDataR = do
let tutorialTable = [whamlet|Übungsgruppen werden momentan leider noch nicht unterstützt.|] let tutorialTable = [whamlet|Übungsgruppen werden momentan leider noch nicht unterstützt.|]
-- Delete Button -- Delete Button
(btnWdgt, btnEnctype) <- generateFormPost (buttonForm :: Form BtnDelete) (btnWdgt, btnEnctype) <- generateFormPost (buttonForm :: Form ButtonDelete)
defaultLayout $ do defaultLayout $ do
let delWdgt = $(widgetFile "widgets/data-delete") let delWdgt = $(widgetFile "widgets/data-delete")
$(widgetFile "profileData") $(widgetFile "profileData")

View File

@ -143,25 +143,15 @@ makeSheetForm msId template = identForm FIDsheet $ \html -> do
getSheetCurrentR :: TermId -> SchoolId -> CourseShorthand -> Handler Html getSheetCurrentR :: TermId -> SchoolId -> CourseShorthand -> Handler Html
getSheetCurrentR tid ssh csh = runDB $ do getSheetCurrentR tid ssh csh = runDB $ do
now <- liftIO getCurrentTime let redi shn = redirectAccess $ CSheetR tid ssh csh shn SShowR
sheets <- E.select . E.from $ \(course `E.InnerJoin` sheet) -> do shn <- sheetCurrent tid ssh csh
E.on $ sheet E.^. SheetCourse E.==. course E.^. CourseId maybe notFound redi shn
E.where_ $ sheet E.^. SheetActiveTo E.>. E.val now
E.&&. sheet E.^. SheetActiveFrom E.<=. E.val now
E.&&. course E.^. CourseTerm E.==. E.val tid
E.&&. course E.^. CourseSchool E.==. E.val ssh
E.&&. course E.^. CourseShorthand E.==. E.val csh
E.orderBy [E.asc $ sheet E.^. SheetActiveFrom]
E.limit 1
return $ sheet E.^. SheetName
case sheets of
(E.Value shn):_ -> redirectAccess $ CSheetR tid ssh csh shn SShowR
_ -> notFound
getSheetOldUnassigned :: TermId -> SchoolId -> CourseShorthand -> Handler () getSheetOldUnassigned :: TermId -> SchoolId -> CourseShorthand -> Handler ()
getSheetOldUnassigned tid ssh csh = runDB $ do getSheetOldUnassigned tid ssh csh = runDB $ do
shn' <- sheetOldUnassigned tid ssh csh let redi shn = redirectAccess $ CSheetR tid ssh csh shn SSubsR
maybe notFound (\shn -> redirectAccess $ CSheetR tid ssh csh shn SSubsR) shn' shn <- sheetOldUnassigned tid ssh csh
maybe notFound redi shn
getSheetListR :: TermId -> SchoolId -> CourseShorthand -> Handler Html getSheetListR :: TermId -> SchoolId -> CourseShorthand -> Handler Html
getSheetListR tid ssh csh = do getSheetListR tid ssh csh = do
@ -287,15 +277,15 @@ getSheetListR tid ssh csh = do
$(widgetFile "sheetList") $(widgetFile "sheetList")
data ButtonGeneratePseudonym = BtnGenerate data ButtonGeneratePseudonym = BtnGenerate
deriving (Enum, Eq, Ord, Bounded, Read, Show) deriving (Enum, Eq, Ord, Bounded, Read, Show, Generic, Typeable)
instance Universe ButtonGeneratePseudonym instance Universe ButtonGeneratePseudonym
instance Finite ButtonGeneratePseudonym instance Finite ButtonGeneratePseudonym
nullaryPathPiece ''ButtonGeneratePseudonym (camelToPathPiece' 1) nullaryPathPiece ''ButtonGeneratePseudonym (camelToPathPiece' 1)
instance Button UniWorX ButtonGeneratePseudonym where instance Button UniWorX ButtonGeneratePseudonym where
label BtnGenerate = [whamlet|_{MsgSheetGeneratePseudonym}|] btnLabel BtnGenerate = [whamlet|_{MsgSheetGeneratePseudonym}|]
cssClass BtnGenerate = BCDefault btnClasses BtnGenerate = [BCIsButton, BCDefault]
-- Show single sheet -- Show single sheet
getSShowR :: TermId -> SchoolId -> CourseShorthand -> SheetName -> Handler Html getSShowR :: TermId -> SchoolId -> CourseShorthand -> SheetName -> Handler Html
@ -435,11 +425,17 @@ getSFileR tid ssh csh shn typ title = do
getSheetNewR :: TermId -> SchoolId -> CourseShorthand -> Handler Html getSheetNewR :: TermId -> SchoolId -> CourseShorthand -> Handler Html
getSheetNewR tid ssh csh = do getSheetNewR tid ssh csh = do
parShn <- runInputGetResult $ iopt ciField "shn"
let searchShn sheet = case parShn of
(FormSuccess (Just shn)) -> E.where_ $ sheet E.^. SheetName E.==. E.val shn
-- (FormFailure msgs) -> -- not in MonadHandler anymore -- forM_ msgs (addMessage Error . toHtml)
_other -> return ()
lastSheets <- runDB $ E.select . E.from $ \(course `E.InnerJoin` sheet) -> do lastSheets <- runDB $ E.select . E.from $ \(course `E.InnerJoin` sheet) -> do
E.on $ course E.^. CourseId E.==. sheet E.^. SheetCourse E.on $ course E.^. CourseId E.==. sheet E.^. SheetCourse
E.where_ $ course E.^. CourseTerm E.==. E.val tid E.where_ $ course E.^. CourseTerm E.==. E.val tid
E.&&. course E.^. CourseSchool E.==. E.val ssh E.&&. course E.^. CourseSchool E.==. E.val ssh
E.&&. course E.^. CourseShorthand E.==. E.val csh E.&&. course E.^. CourseShorthand E.==. E.val csh
searchShn sheet
-- let lastSheetEdit = E.sub_select . E.from $ \sheetEdit -> do -- let lastSheetEdit = E.sub_select . E.from $ \sheetEdit -> do
-- E.where_ $ sheetEdit E.^. SheetEditSheet E.==. sheet E.^. SheetId -- E.where_ $ sheetEdit E.^. SheetEditSheet E.==. sheet E.^. SheetId
-- return . E.max_ $ sheetEdit E.^. SheetEditTime -- return . E.max_ $ sheetEdit E.^. SheetEditTime

View File

@ -15,8 +15,6 @@ import qualified Data.Char as Char
import qualified Data.CaseInsensitive as CI import qualified Data.CaseInsensitive as CI
import qualified Data.Foldable as Foldable
-- import Yesod.Core -- import Yesod.Core
import qualified Data.Text as T import qualified Data.Text as T
-- import Yesod.Form.Types -- import Yesod.Form.Types
@ -51,64 +49,55 @@ import Data.Aeson.Text (encodeToLazyText)
-- Buttons (new version ) -- -- Buttons (new version ) --
---------------------------- ----------------------------
data BtnDelete = BtnDelete data ButtonDelete = BtnDelete
deriving (Enum, Eq, Ord, Bounded, Read, Show) deriving (Enum, Eq, Ord, Bounded, Read, Show, Generic, Typeable)
instance Universe ButtonDelete
instance Finite ButtonDelete
instance Universe BtnDelete nullaryPathPiece ''ButtonDelete $ camelToPathPiece' 1
instance Finite BtnDelete
nullaryPathPiece ''BtnDelete $ camelToPathPiece' 1 embedRenderMessage ''UniWorX ''ButtonDelete id
instance Button UniWorX ButtonDelete where
btnClasses BtnDelete = [BCIsButton, BCDanger]
instance Button UniWorX BtnDelete where data ButtonRegister = BtnRegister | BtnDeregister
label BtnDelete = [whamlet|_{MsgBtnDelete}|] deriving (Enum, Eq, Ord, Bounded, Read, Show, Generic, Typeable)
instance Universe ButtonRegister
instance Finite ButtonRegister
cssClass BtnDelete = BCDanger nullaryPathPiece ''ButtonRegister $ camelToPathPiece' 1
data RegisterButton = BtnRegister | BtnDeregister embedRenderMessage ''UniWorX ''ButtonRegister id
deriving (Enum, Eq, Ord, Bounded, Read, Show) instance Button UniWorX ButtonRegister where
btnClasses BtnRegister = [BCIsButton, BCPrimary]
btnClasses BtnDeregister = [BCIsButton, BCDanger]
instance Universe RegisterButton data ButtonHijack = BtnHijack
instance Finite RegisterButton deriving (Enum, Eq, Ord, Bounded, Read, Show, Generic, Typeable)
instance Universe ButtonHijack
instance Finite ButtonHijack
nullaryPathPiece ''RegisterButton $ camelToPathPiece' 1 nullaryPathPiece ''ButtonHijack $ camelToPathPiece' 1
instance Button UniWorX RegisterButton where embedRenderMessage ''UniWorX ''ButtonHijack id
label BtnRegister = [whamlet|_{MsgBtnRegister}|] instance Button UniWorX ButtonHijack where
label BtnDeregister = [whamlet|_{MsgBtnDeregister}|] btnClasses BtnHijack = [BCIsButton, BCDefault]
cssClass BtnRegister = BCPrimary data ButtonSubmitDelete = BtnSubmit' | BtnDelete'
cssClass BtnDeregister = BCDanger deriving (Enum, Eq, Ord, Bounded, Read, Show, Generic, Typeable)
data AdminHijackUserButton = BtnHijack instance Universe ButtonSubmitDelete
deriving (Enum, Eq, Ord, Bounded, Read, Show) instance Finite ButtonSubmitDelete
instance Universe AdminHijackUserButton embedRenderMessage ''UniWorX ''ButtonSubmitDelete $ dropSuffix "'"
instance Finite AdminHijackUserButton instance Button UniWorX ButtonSubmitDelete where
btnClasses BtnSubmit' = [BCIsButton, BCPrimary]
nullaryPathPiece ''AdminHijackUserButton $ camelToPathPiece' 1 btnClasses BtnDelete' = [BCIsButton, BCDanger]
instance Button UniWorX AdminHijackUserButton where
label BtnHijack = [whamlet|_{MsgBtnHijack}|]
cssClass BtnHijack = BCDefault
data BtnSubmitDelete = BtnSubmit' | BtnDelete'
deriving (Enum, Eq, Ord, Bounded, Read, Show)
instance Universe BtnSubmitDelete
instance Finite BtnSubmitDelete
instance Button UniWorX BtnSubmitDelete where
label BtnSubmit' = [whamlet|_{MsgBtnSubmit}|]
label BtnDelete' = [whamlet|_{MsgBtnDelete}|]
cssClass BtnSubmit' = BCPrimary
cssClass BtnDelete' = BCDanger
btnValidate _ BtnSubmit' = True btnValidate _ BtnSubmit' = True
btnValidate _ BtnDelete' = False btnValidate _ BtnDelete' = False
nullaryPathPiece ''BtnSubmitDelete $ camelToPathPiece' 1 . dropSuffix "'" nullaryPathPiece ''ButtonSubmitDelete $ camelToPathPiece' 1 . dropSuffix "'"
-- -- Looks like a button, but is just a link (e.g. for create course, etc.) -- -- Looks like a button, but is just a link (e.g. for create course, etc.)
@ -118,8 +107,14 @@ nullaryPathPiece ''BtnSubmitDelete $ camelToPathPiece' 1 . dropSuffix "'"
-- instance PathPiece LinkButton where -- instance PathPiece LinkButton where
-- LinkButton route = ??? -- LinkButton route = ???
linkButton :: Widget -> ButtonCssClass UniWorX -> Route UniWorX -> Widget -- Alternative: Handler.Utils.simpleLink linkButton :: Widget -> [ButtonClass UniWorX] -> SomeRoute UniWorX -> Widget -- Alternative: Handler.Utils.simpleLink
linkButton lbl cls url = [whamlet| <a href=@{url} .btn .#{bcc2txt cls} role=button>^{lbl} |] linkButton lbl cls url = do
url' <- toTextUrl url
[whamlet|
$newline never
<a href=#{url'} class=#{unwords $ map toPathPiece cls} role=button>
^{lbl}
|]
-- [whamlet| -- [whamlet|
-- <form method=post action=@{url}> -- <form method=post action=@{url}>
-- <input type="hidden" name="_formid" value="identify-linkButton"> -- <input type="hidden" name="_formid" value="identify-linkButton">
@ -128,31 +123,16 @@ linkButton lbl cls url = [whamlet| <a href=@{url} .btn .#{bcc2txt cls} role=butt
-- <input .btn .#{bcc2txt cls} type="submit" value=^{lbl}> -- <input .btn .#{bcc2txt cls} type="submit" value=^{lbl}>
-- buttonForm :: Button a => Markup -> MForm (HandlerT UniWorX IO) (FormResult a, (WidgetT UniWorX IO ())) -- buttonForm :: (Button UniWorX a, Finite a) => Markup -> MForm (HandlerT UniWorX IO) (FormResult a, Widget)
buttonForm :: (Button UniWorX a, Show a) => Form a buttonForm :: (Button UniWorX a, Finite a) => Form a
buttonForm csrf = do buttonForm csrf = do
buttonIdent <- newFormIdent (res, ($ []) -> fViews) <- aFormToForm . disambiguateButtons $ combinedButtonFieldF ""
let button b = mopt (buttonField b) ("n/a"{ fsName = Just buttonIdent }) Nothing return (res, [whamlet|
(results, btnViews) <- unzip <$> mapM button [minBound..maxBound] $newline never
let widget = #{csrf}
[whamlet| $forall bView <- fViews
#{csrf} ^{fvInput bView}
$forall bView <- btnViews |])
^{fvInput bView}
|]
return (accResult results,widget)
where
accResult :: Foldable f => f (FormResult (Maybe a)) -> FormResult a
accResult = Foldable.foldr accResult' FormMissing
accResult' :: FormResult (Maybe a) -> FormResult a -> FormResult a
-- Find the single FormSuccess Just _; Expected behaviour: all buttons deliver FormFailure, except for one.
accResult' (FormSuccess (Just _)) (FormSuccess _) = FormFailure ["Ambiguous button parse"]
accResult' (FormSuccess (Just x)) _ = FormSuccess x
accResult' _ x@(FormSuccess _) = x --Safe: most buttons deliver FormFailure, one delivers FormSuccess
accResult' (FormSuccess Nothing) x = x
accResult' FormMissing _ = FormMissing
accResult' (FormFailure errs) _ = FormFailure errs

View File

@ -519,7 +519,7 @@ dbParamsFormWrap DBParamsForm{..} tableForm frag = do
return . (res,) $ do return . (res,) $ do
btnId <- newIdent btnId <- newIdent
act <- traverse toTextUrl dbParamsFormAction act <- traverse toTextUrl dbParamsFormAction
let submitField :: Field Handler SubmitButton let submitField :: Field Handler ButtonSubmit
submitField = buttonField BtnSubmit submitField = buttonField BtnSubmit
submitView :: Widget submitView :: Widget
submitView = fieldView submitField btnId "" mempty (Right BtnSubmit) False submitView = fieldView submitField btnId "" mempty (Right BtnSubmit) False

View File

@ -364,7 +364,7 @@ mcons :: Maybe a -> [a] -> [a]
mcons Nothing xs = xs mcons Nothing xs = xs
mcons (Just x) xs = x:xs mcons (Just x) xs = x:xs
newtype NTop a = NTop a -- treat Nothing as Top for Ord (Maybe a); default implementation treats Nothing as bottom newtype NTop a = NTop { nBot :: a } -- treat Nothing as Top for Ord (Maybe a); default implementation treats Nothing as bottom
instance Eq a => Eq (NTop (Maybe a)) where instance Eq a => Eq (NTop (Maybe a)) where
(NTop x) == (NTop y) = x == y (NTop x) == (NTop y) = x == y

View File

@ -7,7 +7,6 @@ import Settings
import qualified Text.Blaze.Internal as Blaze (null) import qualified Text.Blaze.Internal as Blaze (null)
import qualified Data.Text as T import qualified Data.Text as T
import qualified Data.Char as Char
import Data.CaseInsensitive (CI) import Data.CaseInsensitive (CI)
import qualified Data.CaseInsensitive as CI import qualified Data.CaseInsensitive as CI
@ -200,37 +199,36 @@ identForm = identifyForm . toPathPiece
-- Buttons (new version ) -- -- Buttons (new version ) --
---------------------------- ----------------------------
data family ButtonCssClass site :: * data family ButtonClass site :: *
bcc2txt :: Show (ButtonCssClass site) => ButtonCssClass site -> Text -- a Hack; maybe define Read/Show manually class (PathPiece a, PathPiece (ButtonClass site), RenderMessage site ButtonMessage) => Button site a where
bcc2txt bcc = T.pack $ "btn-" ++ (Char.toLower <$> drop 2 (show bcc)) btnLabel :: a -> WidgetT site IO ()
class (Enum a, Bounded a, Ord a, PathPiece a) => Button site a where default btnLabel :: RenderMessage site a => a -> WidgetT site IO ()
label :: a -> WidgetT site IO () btnLabel = toWidget <=< ap getMessageRender . return
label = toWidget . toPathPiece
btnValidate :: forall p. p site -> a -> Bool btnValidate :: forall p. p site -> a -> Bool
btnValidate _ _ = True btnValidate _ _ = True
cssClass :: a -> ButtonCssClass site btnClasses :: a -> [ButtonClass site]
btnClasses _ = []
data ButtonMessage = MsgAmbiguousButtons data ButtonMessage = MsgAmbiguousButtons
| MsgWrongButtonValue | MsgWrongButtonValue
| MsgMultipleButtonValues | MsgMultipleButtonValues
deriving (Eq, Ord, Enum, Bounded, Read, Show, Generic, Typeable)
data SubmitButton = BtnSubmit data ButtonSubmit = BtnSubmit
deriving (Enum, Eq, Ord, Bounded, Read, Show) deriving (Eq, Ord, Enum, Bounded, Read, Show, Generic, Typeable)
instance Universe SubmitButton instance Universe ButtonSubmit
instance Finite SubmitButton instance Finite ButtonSubmit
nullaryPathPiece ''SubmitButton $ camelToPathPiece' 1 nullaryPathPiece ''ButtonSubmit $ camelToPathPiece' 1
buttonField :: forall a m. buttonField :: forall a m.
( Button (HandlerSite m) a ( Button (HandlerSite m) a
, Show (ButtonCssClass (HandlerSite m)) , MonadHandler m
, RenderMessage (HandlerSite m) ButtonMessage
, Monad m
) => a -> Field m a ) => a -> Field m a
-- | Already validates that the correct button press was received (result only neccessary for combinedButtonField) -- | Already validates that the correct button press was received (result only neccessary for combinedButtonField)
buttonField btn = Field{..} buttonField btn = Field{..}
@ -239,12 +237,12 @@ buttonField btn = Field{..}
fieldView :: FieldViewFunc m a fieldView :: FieldViewFunc m a
fieldView fid name attrs _val _ = let fieldView fid name attrs _val _ = let
cssClass' :: ButtonCssClass (HandlerSite m)
cssClass' = cssClass btn
validate = btnValidate (Proxy @(HandlerSite m)) btn validate = btnValidate (Proxy @(HandlerSite m)) btn
classes :: [ButtonClass (HandlerSite m)]
classes = btnClasses btn
in [whamlet| in [whamlet|
$newline never $newline never
<button .btn .#{bcc2txt cssClass'} type=submit name=#{name} value=#{toPathPiece btn} *{attrs} ##{fid} :not validate:formnovalidate>^{label btn} <button class=#{unwords $ map toPathPiece classes} type=submit name=#{name} value=#{toPathPiece btn} *{attrs} ##{fid} :not validate:formnovalidate>^{btnLabel btn}
|] |]
fieldParse [] [] = return $ Right Nothing fieldParse [] [] = return $ Right Nothing
@ -255,8 +253,6 @@ buttonField btn = Field{..}
combinedButtonField :: forall a m. combinedButtonField :: forall a m.
( Button (HandlerSite m) a ( Button (HandlerSite m) a
, Show (ButtonCssClass (HandlerSite m))
, RenderMessage (HandlerSite m) ButtonMessage
, MonadHandler m , MonadHandler m
) => [a] -> FieldSettings (HandlerSite m) -> AForm m [Maybe a] ) => [a] -> FieldSettings (HandlerSite m) -> AForm m [Maybe a]
combinedButtonField bs FieldSettings{..} = formToAForm $ do combinedButtonField bs FieldSettings{..} = formToAForm $ do
@ -280,8 +276,6 @@ combinedButtonField bs FieldSettings{..} = formToAForm $ do
combinedButtonFieldF :: forall m a. combinedButtonFieldF :: forall m a.
( Button (HandlerSite m) a ( Button (HandlerSite m) a
, Show (ButtonCssClass (HandlerSite m))
, RenderMessage (HandlerSite m) ButtonMessage
, Finite a , Finite a
, MonadHandler m , MonadHandler m
) => FieldSettings (HandlerSite m) -> AForm m [Maybe a] ) => FieldSettings (HandlerSite m) -> AForm m [Maybe a]
@ -298,26 +292,22 @@ disambiguateButtons = traverseAForm $ \case
combinedButtonField_ :: forall a m. combinedButtonField_ :: forall a m.
( Button (HandlerSite m) a ( Button (HandlerSite m) a
, Show (ButtonCssClass (HandlerSite m))
, RenderMessage (HandlerSite m) ButtonMessage
, MonadHandler m , MonadHandler m
) => [a] -> FieldSettings (HandlerSite m) -> AForm m () ) => [a] -> FieldSettings (HandlerSite m) -> AForm m ()
combinedButtonField_ = (void .) . combinedButtonField combinedButtonField_ = (void .) . combinedButtonField
combinedButtonFieldF_ :: forall m a p. combinedButtonFieldF_ :: forall m a p.
( Button (HandlerSite m) a ( Button (HandlerSite m) a
, Show (ButtonCssClass (HandlerSite m))
, RenderMessage (HandlerSite m) ButtonMessage
, MonadHandler m , MonadHandler m
, Finite a , Finite a
) => p a -> FieldSettings (HandlerSite m) -> AForm m () ) => p a -> FieldSettings (HandlerSite m) -> AForm m ()
combinedButtonFieldF_ _ = void . combinedButtonFieldF @m @a combinedButtonFieldF_ _ = void . combinedButtonFieldF @m @a
submitButton :: (Button (HandlerSite m) SubmitButton, Show (ButtonCssClass (HandlerSite m)), MonadHandler m, RenderMessage (HandlerSite m) ButtonMessage) => AForm m () submitButton :: (Button (HandlerSite m) ButtonSubmit, MonadHandler m) => AForm m ()
submitButton = combinedButtonFieldF_ (Proxy @SubmitButton) "" submitButton = combinedButtonFieldF_ (Proxy @ButtonSubmit) ""
autosubmitButton :: (Button (HandlerSite m) SubmitButton, Show (ButtonCssClass (HandlerSite m)), MonadHandler m, RenderMessage (HandlerSite m) ButtonMessage) => AForm m () autosubmitButton :: (Button (HandlerSite m) ButtonSubmit, MonadHandler m) => AForm m ()
autosubmitButton = combinedButtonFieldF_ (Proxy @SubmitButton) $ "" & addAutosubmit autosubmitButton = combinedButtonFieldF_ (Proxy @ButtonSubmit) $ "" & addAutosubmit
------------------- -------------------
-- Custom Fields -- -- Custom Fields --

View File

@ -3,6 +3,28 @@ module Utils.Sheet where
import Import.NoFoundation import Import.NoFoundation
import qualified Database.Esqueleto as E import qualified Database.Esqueleto as E
-- DB Queries for Sheets that are used in several places
sheetCurrent :: MonadIO m => TermId -> SchoolId -> CourseShorthand -> SqlReadT m (Maybe SheetName)
sheetCurrent tid ssh csh = do
now <- liftIO getCurrentTime
sheets <- E.select . E.from $ \(course `E.InnerJoin` sheet) -> do
E.on $ sheet E.^. SheetCourse E.==. course E.^. CourseId
E.where_ $ sheet E.^. SheetActiveTo E.>. E.val now
E.&&. sheet E.^. SheetActiveFrom E.<=. E.val now
E.&&. course E.^. CourseTerm E.==. E.val tid
E.&&. course E.^. CourseSchool E.==. E.val ssh
E.&&. course E.^. CourseShorthand E.==. E.val csh
E.orderBy [E.asc $ sheet E.^. SheetActiveTo]
E.limit 1
return $ sheet E.^. SheetName
return $ case sheets of
[] -> Nothing
[E.Value shn] -> Just shn
_ -> error "SQL Query with limit 1 returned more than one result"
sheetOldUnassigned :: MonadIO m => TermId -> SchoolId -> CourseShorthand -> SqlReadT m (Maybe SheetName) sheetOldUnassigned :: MonadIO m => TermId -> SchoolId -> CourseShorthand -> SqlReadT m (Maybe SheetName)
sheetOldUnassigned tid ssh csh = do sheetOldUnassigned tid ssh csh = do
now <- liftIO getCurrentTime now <- liftIO getCurrentTime
@ -12,10 +34,10 @@ sheetOldUnassigned tid ssh csh = do
E.&&. course E.^. CourseTerm E.==. E.val tid E.&&. course E.^. CourseTerm E.==. E.val tid
E.&&. course E.^. CourseSchool E.==. E.val ssh E.&&. course E.^. CourseSchool E.==. E.val ssh
E.&&. course E.^. CourseShorthand E.==. E.val csh E.&&. course E.^. CourseShorthand E.==. E.val csh
E.where_ . E.exists . E.from $ \submission -> do E.where_ . E.exists . E.from $ \submission ->
E.where_ $ submission E.^. SubmissionSheet E.==. sheet E.^. SheetId E.where_ $ submission E.^. SubmissionSheet E.==. sheet E.^. SheetId
E.&&. E.isNothing (submission E.^. SubmissionRatingBy) E.&&. E.isNothing (submission E.^. SubmissionRatingBy)
E.orderBy [E.desc $ sheet E.^. SheetActiveTo] E.orderBy [E.asc $ sheet E.^. SheetActiveTo]
E.limit 1 E.limit 1
return $ sheet E.^. SheetName return $ sheet E.^. SheetName
return $ case sheets of return $ case sheets of

View File

@ -1,10 +1,9 @@
<div .container> <div .container>
<dl .deflist> <dl .deflist>
$maybe school <- schoolMB <dt .deflist__dt>Fakultät/Institut
<dt .deflist__dt>Fakultät/Institut <dd .deflist__dd>
<dd .deflist__dd> <div>
<div> #{schoolName}
#{schoolName school}
$maybe descr <- courseDescription course $maybe descr <- courseDescription course
<dt .deflist__dt>_{MsgCourseDescription} <dt .deflist__dt>_{MsgCourseDescription}
@ -33,20 +32,27 @@ $# $if NTop (Just 0) < NTop (courseCapacity course)
#{participants} #{participants}
$maybe capacity <- courseCapacity course $maybe capacity <- courseCapacity course
\ von #{capacity} \ von #{capacity}
$maybe regFrom <- mRegFrom $maybe regFrom <- mRegFrom
<dt .deflist__dt>Anmeldezeitraum <dt .deflist__dt>Anmeldezeitraum
<dd .deflist__dd> <dd .deflist__dd>
<div>
Ab #{regFrom}
$maybe regTo <- mRegTo
\ bis #{regTo}
$maybe dereg <- mDereg
<div> <div>
Ab #{regFrom} \ <em>Achtung:</em>
$maybe regTo <- mRegTo \ Abmeldung nur bis #{dereg} erlaubt.
\ bis #{regTo} $if registrationOpen || isJust mRegAt
$if registrationOpen
<dt .deflist__dt> <dt .deflist__dt>
<dd .deflist__dd> <dd .deflist__dd>
<div .course__registration> <div .course__registration>
<form method=post action=@{CourseR tid ssh csh CRegisterR} enctype=#{regEnctype}> $if registrationOpen
$# regWidget is defined through templates/widgets/registerForm <form method=post action=@{CourseR tid ssh csh CRegisterR} enctype=#{regEnctype}>
^{regWidget} $# regWidget is defined through templates/widgets/registerForm
^{regWidget}
$maybe date <- mRegAt
_{MsgRegisteredSince date}
<dt .deflist__dt> <dt .deflist__dt>
Material Material
<dd .deflist__dd> <dd .deflist__dd>

View File

@ -3,6 +3,6 @@ $newline never
<form method=GET action=#{filterAction} enctype=#{filterEnctype}> <form method=GET action=#{filterAction} enctype=#{filterEnctype}>
^{filterWgdt} ^{filterWgdt}
<button> <button>
^{label BtnSubmit} ^{btnLabel BtnSubmit}
<section> <section>
^{scrolltable} ^{scrolltable}

View File

@ -5,4 +5,3 @@ $maybe secretView <- msecretView
^{fvInput secretView} ^{fvInput secretView}
$# Always display register/deregister button $# Always display register/deregister button
^{fvInput btnView} ^{fvInput btnView}