module Handler.Course.User ( getCUserR, postCUserR ) where import Import import Utils.Form import Handler.Utils import Database.Esqueleto.Utils.TH import Data.Function ((&)) import qualified Database.Esqueleto as E import Text.Blaze.Html.Renderer.Text (renderHtml) import Handler.Course.Register getCUserR, postCUserR :: TermId -> SchoolId -> CourseShorthand -> CryptoUUIDUser -> Handler Html getCUserR = postCUserR postCUserR tid ssh csh uCId = do -- Has authorization checks (OR): -- -- - User is current member of course -- - User has submitted in course -- - User is member of registered group for course -- - User is member of a tutorial for course -- - User is corrector for course -- - User is a tutor for course -- - User is a lecturer for course let currentRoute = CourseR tid ssh csh (CUserR uCId) dozentId <- requireAuthId uid <- decrypt uCId -- DB reads (cid, User{..}, mRegistration, thisUniqueNote, noteText, noteEdits, studies) <- runDB $ do cid <- getKeyBy404 $ TermSchoolCourseShort tid ssh csh -- Abfrage Benutzerdaten user <- get404 uid registration <- getBy (UniqueParticipant uid cid) -- Abfrage Teilnehmernotiz let thisUniqueNote = UniqueCourseUserNote uid cid mbNoteEnt <- getBy thisUniqueNote (noteText,noteEdits) <- case mbNoteEnt of Nothing -> return (Nothing,[]) (Just (Entity noteKey CourseUserNote{courseUserNoteNote})) -> do noteEdits <- E.select $ E.from $ \(edit `E.InnerJoin` usr) -> do E.on $ edit E.^. CourseUserNoteEditUser E.==. usr E.^. UserId E.where_ $ edit E.^. CourseUserNoteEditNote E.==. E.val noteKey E.orderBy [E.desc $ edit E.^. CourseUserNoteEditTime] E.limit 1 -- more will be shown, if changed here return (edit E.^. CourseUserNoteEditTime, usr E.^. UserEmail, usr E.^. UserDisplayName, usr E.^. UserSurname) return (Just courseUserNoteNote, $(unValueN 4) <$> noteEdits) -- Abfrage Studiengänge studies <- E.select $ E.from $ \(studydegree `E.InnerJoin` studyfeat `E.InnerJoin` studyterms) -> do E.where_ $ studyfeat E.^. StudyFeaturesUser E.==. E.val uid E.on $ studyfeat E.^. StudyFeaturesField E.==. studyterms E.^. StudyTermsId E.on $ studyfeat E.^. StudyFeaturesDegree E.==. studydegree E.^. StudyDegreeId return (studyfeat, studydegree, studyterms) return (cid, user, registration, thisUniqueNote, noteText, noteEdits, studies) let editByWgt = [whamlet| $forall (etime,_eemail,ename,_esurname) <- noteEdits
_{MsgLastEdit} ^{editedByW SelFormatDateTime etime ename} |] -- _{MsgLastEdit} ^{formatTimeW SelFormatDateTime etime} ^{nameWidget ename esurname} ((noteRes, noteView), noteEnctype) <- runFormPost . identifyForm FIDcUserNote . renderAForm FormStandard $ aopt (annotateField editByWgt htmlField') (fslpI MsgCourseUserNote "HTML" & setTooltip MsgCourseUserNoteTooltip) (Just noteText) let noteFrag :: Text noteFrag = "notes" noteWidget = wrapForm noteView FormSettings { formMethod = POST , formAction = Just . SomeRoute $ currentRoute :#: noteFrag , formEncoding = noteEnctype , formAttrs = [] , formSubmit = FormSubmit , formAnchor = Just noteFrag } formResult noteRes $ \mbNote -> do now <- liftIO getCurrentTime runDB $ case mbNote of Nothing -> do -- must delete all edits due to foreign key constraints, which does not make sense -> refactor! maybeM (return ()) (\nk -> deleteWhere [CourseUserNoteEditNote ==. nk]) (getKeyBy thisUniqueNote) deleteBy thisUniqueNote addMessageI Info MsgCourseUserNoteDeleted _ | (renderHtml <$> mbNote) == (renderHtml <$> noteText) -> return () -- no changes (Just note) -> do (Entity noteKey _) <- upsertBy thisUniqueNote (CourseUserNote cid uid note) [CourseUserNoteNote =. note] void . insert $ CourseUserNoteEdit dozentId now noteKey addMessageI Success MsgCourseUserNoteSaved redirect $ currentRoute :#: noteFrag -- reload page after post ((regFieldRes, regFieldView), regFieldEnctype) <- runFormPost . identifyForm FIDcRegField $ \csrf -> let currentField :: Maybe (Maybe StudyFeaturesId) currentField = courseParticipantField . entityVal <$> mRegistration in over _2 ((toWidget csrf <>) . fvInput) <$> mreq (studyFeaturesFieldFor Nothing True (maybeToList $ join currentField) $ Just uid) ("" & addAutosubmit) currentField let registrationFieldFrag :: Text registrationFieldFrag = "registration-field" regFieldWidget = wrapForm regFieldView FormSettings { formMethod = POST , formAction = Just . SomeRoute $ currentRoute :#: registrationFieldFrag , formEncoding = regFieldEnctype , formAttrs = [] , formSubmit = FormAutoSubmit , formAnchor = Just registrationFieldFrag } for_ mRegistration $ \(Entity pId CourseParticipant{..}) -> formResult regFieldRes $ \courseParticipantField' -> do runDB $ do update pId [ CourseParticipantField =. courseParticipantField' ] audit $ TransactionCourseParticipantEdit cid uid addMessageI Success MsgCourseStudyFeatureUpdated redirect $ currentRoute :#: registrationFieldFrag let regButton | Just _ <- mRegistration = BtnCourseDeregister | otherwise = BtnCourseRegister ((regButtonRes, regButtonView), regButtonEnctype) <- runFormPost . identifyForm FIDcRegButton $ buttonForm' [regButton] let registrationButtonFrag :: Text registrationButtonFrag = "registration-button" regButtonWidget = wrapForm regButtonView FormSettings { formMethod = POST , formAction = Just . SomeRoute $ currentRoute :#: registrationButtonFrag , formEncoding = regButtonEnctype , formAttrs = [] , formSubmit = FormNoSubmit , formAnchor = Just registrationButtonFrag } formResult regButtonRes $ \case BtnCourseDeregister | Just (Entity pId _) <- mRegistration -> do runDB $ delete pId addMessageIconI Info IconEnrolFalse MsgCourseDeregisterOk redirect $ CourseR tid ssh csh CUsersR | otherwise -> invalidArgs ["User not registered"] BtnCourseRegister -> do now <- liftIO getCurrentTime let field | [(Entity featId _, _, _)] <- filter (\(Entity _ StudyFeatures{..}, _, _) -> studyFeaturesValid) studies = Just featId | otherwise = Nothing pId <- runDB $ do pId <- insertUnique $ CourseParticipant cid uid now field False when (is _Just pId) $ audit $ TransactionCourseParticipantEdit cid uid return pId case pId of Just _ -> do addMessageIconI Success IconEnrolTrue MsgCourseRegisterOk redirect currentRoute Nothing -> invalidArgs ["User already registered"] _other -> fail "Invalid @regButton@" mRegAt <- for (courseParticipantRegistration . entityVal <$> mRegistration) $ formatTime SelFormatDateTime -- generate output let headingLong = [whamlet|^{nameWidget userDisplayName userSurname} - _{MsgCourseMemberOf} #{csh} #{tid}|] headingShort = prependCourseTitle tid ssh csh $ SomeMessage userDisplayName siteLayout headingLong $ do setTitleI headingShort $(widgetFile "course-user")