|
|
|
|
@ -106,51 +106,7 @@ makeCourseForm miButtonAction template = identifyForm FIDcourse . validateFormDB
|
|
|
|
|
-> return (termsSetField [cfTerm cform], [cfTerm cform])
|
|
|
|
|
_allOtherCases -> (termsAllowedField, ) . Set.toList <$> runDB getActiveTerms
|
|
|
|
|
|
|
|
|
|
let miAdd :: ListPosition -> Natural -> ListLength -> (Text -> Text) -> FieldView UniWorX -> Maybe (Form (Map ListPosition (Either UserEmail UserId) -> FormResult (Map ListPosition (Either UserEmail UserId))))
|
|
|
|
|
miAdd _ _ _ nudge btn = Just $ \csrf -> do
|
|
|
|
|
(addRes, addView) <- mpreq (multiUserInvitationField $ MUILookupAnyUser Nothing) (fslI MsgCourseLecturerEmail & addName (nudge "email") & addPlaceholder (mr MsgLdapIdentificationOrEmail)) Nothing
|
|
|
|
|
let addRes'' = addRes <&> \newDat oldDat -> if
|
|
|
|
|
| existing <- newDat `Set.intersection` Set.fromList (Map.elems oldDat)
|
|
|
|
|
, not $ Set.null existing
|
|
|
|
|
-> FormFailure [mr MsgCourseLecturerAlreadyAdded]
|
|
|
|
|
| otherwise
|
|
|
|
|
-> FormSuccess . Map.fromList . zip [maybe 0 (succ . fst) $ Map.lookupMax oldDat ..] $ Set.toList newDat
|
|
|
|
|
addView' = $(widgetFile "course/lecturerMassInput/add")
|
|
|
|
|
return (addRes'', addView')
|
|
|
|
|
|
|
|
|
|
miCell :: ListPosition -> Either UserEmail UserId -> Maybe (Maybe LecturerType) -> (Text -> Text) -> Form (Maybe LecturerType)
|
|
|
|
|
miCell _ (Right lid) defType nudge = \csrf -> do
|
|
|
|
|
(lrwRes,lrwView) <- mreq (selectField optionsFinite) (fslI MsgCourseLecturerType & addName (nudge "lecturer-type")) (join defType)
|
|
|
|
|
usr <- liftHandler . runDB $ get404 lid
|
|
|
|
|
let lrwView' = $(widgetFile "course/lecturerMassInput/cellKnown")
|
|
|
|
|
return (Just <$> lrwRes,lrwView')
|
|
|
|
|
miCell _ (Left lEmail) defType nudge = \csrf -> do
|
|
|
|
|
(lrwRes,lrwView) <- mopt (selectField optionsFinite) ("" & addName (nudge "lecturer-type")) defType
|
|
|
|
|
invWarnMsg <- messageIconI Info IconEmail MsgEmailInvitationWarning
|
|
|
|
|
let lrwView' = $(widgetFile "course/lecturerMassInput/cellInvitation")
|
|
|
|
|
return (lrwRes,lrwView')
|
|
|
|
|
|
|
|
|
|
miDelete :: Map ListPosition (Either UserEmail UserId) -- ^ Current shape
|
|
|
|
|
-> ListPosition -- ^ Coordinate to delete
|
|
|
|
|
-> MaybeT (MForm (HandlerFor UniWorX)) (Map ListPosition ListPosition)
|
|
|
|
|
miDelete = miDeleteList
|
|
|
|
|
|
|
|
|
|
miAddEmpty :: ListPosition -> Natural -> ListLength -> Set ListPosition
|
|
|
|
|
miAddEmpty _ _ _ = Set.empty
|
|
|
|
|
|
|
|
|
|
miLayout :: ListLength
|
|
|
|
|
-> Map ListPosition (Either UserEmail UserId, FormResult (Maybe LecturerType)) -- ^ massInput state
|
|
|
|
|
-> Map ListPosition Widget -- ^ Cell widgets
|
|
|
|
|
-> Map ListPosition (FieldView UniWorX) -- ^ Deletion buttons
|
|
|
|
|
-> Map (Natural, ListPosition) Widget -- ^ Addition widgets
|
|
|
|
|
-> Widget
|
|
|
|
|
miLayout lLength _ cellWdgts delButtons addWdgts = $(widgetFile "course/lecturerMassInput/layout")
|
|
|
|
|
|
|
|
|
|
miIdent :: Text
|
|
|
|
|
miIdent = "lecturers"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
lecturerForm :: AForm Handler [Either (UserEmail, Maybe LecturerType) (UserId, LecturerType)]
|
|
|
|
|
let lecturerForm :: AForm Handler [Either (UserEmail, Maybe LecturerType) (UserId, LecturerType)]
|
|
|
|
|
lecturerForm = formToAForm . over (mapped._2) pure . over (mapped._1.mapped) (map liftEither . Map.elems) $ massInput
|
|
|
|
|
MassInput{..}
|
|
|
|
|
(fslI MsgCourseLecturers & setTooltip MsgCourseLecturerRightsIdentical)
|
|
|
|
|
@ -167,6 +123,50 @@ makeCourseForm miButtonAction template = identifyForm FIDcourse . validateFormDB
|
|
|
|
|
unliftEither (Right (lid , lType )) = (Right lid , Just lType)
|
|
|
|
|
unliftEither (Left (lEmail, mLType)) = (Left lEmail, mLType )
|
|
|
|
|
|
|
|
|
|
miAdd :: ListPosition -> Natural -> ListLength -> (Text -> Text) -> FieldView UniWorX -> Maybe (Form (Map ListPosition (Either UserEmail UserId) -> FormResult (Map ListPosition (Either UserEmail UserId))))
|
|
|
|
|
miAdd _ _ _ nudge btn = Just $ \csrf -> do
|
|
|
|
|
(addRes, addView) <- mpreq (multiUserInvitationField $ MUILookupAnyUser Nothing) (fslI MsgCourseLecturerEmail & addName (nudge "email") & addPlaceholder (mr MsgLdapIdentificationOrEmail)) Nothing
|
|
|
|
|
let addRes'' = addRes <&> \newDat oldDat -> if
|
|
|
|
|
| existing <- newDat `Set.intersection` Set.fromList (Map.elems oldDat)
|
|
|
|
|
, not $ Set.null existing
|
|
|
|
|
-> FormFailure [mr MsgCourseLecturerAlreadyAdded]
|
|
|
|
|
| otherwise
|
|
|
|
|
-> FormSuccess . Map.fromList . zip [maybe 0 (succ . fst) $ Map.lookupMax oldDat ..] $ Set.toList newDat
|
|
|
|
|
addView' = $(widgetFile "course/lecturerMassInput/add")
|
|
|
|
|
return (addRes'', addView')
|
|
|
|
|
|
|
|
|
|
miCell :: ListPosition -> Either UserEmail UserId -> Maybe (Maybe LecturerType) -> (Text -> Text) -> Form (Maybe LecturerType)
|
|
|
|
|
miCell _ (Right lid) defType nudge = \csrf -> do
|
|
|
|
|
(lrwRes,lrwView) <- mreq (selectField optionsFinite) (fslI MsgCourseLecturerType & addName (nudge "lecturer-type")) (join defType)
|
|
|
|
|
usr <- liftHandler . runDB $ get404 lid
|
|
|
|
|
let lrwView' = $(widgetFile "course/lecturerMassInput/cellKnown")
|
|
|
|
|
return (Just <$> lrwRes,lrwView')
|
|
|
|
|
miCell _ (Left lEmail) defType nudge = \csrf -> do
|
|
|
|
|
(lrwRes,lrwView) <- mopt (selectField optionsFinite) ("" & addName (nudge "lecturer-type")) defType
|
|
|
|
|
invWarnMsg <- messageIconI Info IconEmail MsgEmailInvitationWarning
|
|
|
|
|
let lrwView' = $(widgetFile "course/lecturerMassInput/cellInvitation")
|
|
|
|
|
return (lrwRes,lrwView')
|
|
|
|
|
|
|
|
|
|
miDelete :: Map ListPosition (Either UserEmail UserId) -- ^ Current shape
|
|
|
|
|
-> ListPosition -- ^ Coordinate to delete
|
|
|
|
|
-> MaybeT (MForm (HandlerFor UniWorX)) (Map ListPosition ListPosition)
|
|
|
|
|
miDelete = miDeleteList
|
|
|
|
|
|
|
|
|
|
miAddEmpty :: ListPosition -> Natural -> ListLength -> Set ListPosition
|
|
|
|
|
miAddEmpty _ _ _ = Set.empty
|
|
|
|
|
|
|
|
|
|
miLayout :: ListLength
|
|
|
|
|
-> Map ListPosition (Either UserEmail UserId, FormResult (Maybe LecturerType)) -- ^ massInput state
|
|
|
|
|
-> Map ListPosition Widget -- ^ Cell widgets
|
|
|
|
|
-> Map ListPosition (FieldView UniWorX) -- ^ Deletion buttons
|
|
|
|
|
-> Map (Natural, ListPosition) Widget -- ^ Addition widgets
|
|
|
|
|
-> Widget
|
|
|
|
|
miLayout lLength _ cellWdgts delButtons addWdgts = $(widgetFile "course/lecturerMassInput/layout")
|
|
|
|
|
|
|
|
|
|
miIdent :: Text
|
|
|
|
|
miIdent = "lecturers"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
(newVisFrom,newRegFrom,newRegTo,newDeRegUntil) <- case template of
|
|
|
|
|
(Just cform) | (Just _cid) <- cfCourseId cform -> return (Nothing,Nothing,Nothing,Nothing)
|
|
|
|
|
_allIOtherCases -> do
|
|
|
|
|
@ -366,6 +366,7 @@ courseEditHandler miButtonAction mbCourseForm = do
|
|
|
|
|
let (invites, adds) = partitionEithers $ cfLecturers res
|
|
|
|
|
insertMany_ $ map (\(lid, lty) -> Lecturer lid cid lty) adds
|
|
|
|
|
sinkInvitationsF lecturerInvitationConfig $ map (\(lEmail, mLty) -> (lEmail, cid, (InvDBDataLecturer mLty, InvTokenDataLecturer))) invites
|
|
|
|
|
void $ upsertCourseQualifications aid cid $ cfQualis res
|
|
|
|
|
insert_ $ CourseEdit aid now cid
|
|
|
|
|
memcachedByInvalidate AuthCacheLecturerList $ Proxy @(Set UserId)
|
|
|
|
|
return insertOkay
|
|
|
|
|
@ -414,11 +415,9 @@ courseEditHandler miButtonAction mbCourseForm = do
|
|
|
|
|
let (invites, adds) = partitionEithers $ cfLecturers res
|
|
|
|
|
insertMany_ $ map (\(lid, lty) -> Lecturer lid cid lty) adds
|
|
|
|
|
sinkInvitationsF lecturerInvitationConfig $ map (\(lEmail, mLty) -> (lEmail, cid, (InvDBDataLecturer mLty, InvTokenDataLecturer))) invites
|
|
|
|
|
|
|
|
|
|
void $ upsertCourseQualifications aid cid $ cfQualis res
|
|
|
|
|
insert_ $ CourseEdit aid now cid
|
|
|
|
|
|
|
|
|
|
memcachedByInvalidate AuthCacheLecturerList $ Proxy @(Set UserId)
|
|
|
|
|
|
|
|
|
|
addMessageI Success $ MsgCourseEditOk tid ssh csh
|
|
|
|
|
return True
|
|
|
|
|
when success $ redirect $ CourseR tid ssh csh CShowR
|
|
|
|
|
@ -429,3 +428,30 @@ courseEditHandler miButtonAction mbCourseForm = do
|
|
|
|
|
{ formAction = Just $ SomeRoute actionUrl
|
|
|
|
|
, formEncoding = formEnctype
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
-- upsertCourseQualifications :: forall m backend . (MonadIO m, PersistStoreWrite backend, PersistQueryRead backend) => UserId -> CourseId -> [(QualificationId, Int)] -> ReaderT backend m Bool
|
|
|
|
|
upsertCourseQualifications :: UserId -> CourseId -> [(QualificationId, Int)] -> YesodJobDB UniWorX Bool -- could be generalized
|
|
|
|
|
upsertCourseQualifications uid cid qualis = do
|
|
|
|
|
let newQualis = Map.fromList qualis
|
|
|
|
|
oldQualis <- Map.fromDistinctAscList . fmap (\Entity{entityKey=k, entityVal=CourseQualification{..}} -> (courseQualificationQualification, (k, courseQualificationSortOrder)))
|
|
|
|
|
<$> selectList [CourseQualificationCourse ==. cid] [Asc CourseQualificationSortOrder]
|
|
|
|
|
-- NOTE: CourseQualification allow the immediate assignment of these qualifications to any enrolled user. Hence SchoolAdmins must not be allowed to assign school-foreign qualifications, see #150
|
|
|
|
|
okSchools <- Set.fromDistinctAscList . fmap (userFunctionSchool . entityVal)
|
|
|
|
|
<$> selectList [UserFunctionUser ==. uid, UserFunctionFunction <-. [SchoolAdmin, SchoolLecturer]] [Asc UserFunctionSchool]
|
|
|
|
|
foldWithKeyMapM oldQualis $ \qu (k, so_old) -> case Map.lookup qu newQualis of
|
|
|
|
|
Just so_new | so_new /= so_old
|
|
|
|
|
-> update k [CourseQualificationSortOrder =. so_new] -- existing CourseQualifications may be re-ordered, regardless of school association
|
|
|
|
|
Nothing -> delete k -- existing CourseQualifications may be removed, regardless of school association
|
|
|
|
|
_ -> return ()
|
|
|
|
|
res <- foldWithKeyMapM (newQualis Map.\\ oldQualis) $ \qu so -> get qu >>= \case
|
|
|
|
|
Just Qualification{qualificationSchool=ssh, qualificationShorthand=qsh}
|
|
|
|
|
| Set.member ssh okSchools ->
|
|
|
|
|
insert_ CourseQualification{courseQualificationQualification = qu, courseQualificationCourse = cid, courseQualificationSortOrder = so}
|
|
|
|
|
$> All True
|
|
|
|
|
| otherwise -> do
|
|
|
|
|
addMessageI Warning $ MsgCourseEditQualificationFailRights qsh ssh
|
|
|
|
|
pure $ All False
|
|
|
|
|
_ -> do
|
|
|
|
|
addMessageI Warning MsgCourseEditQualificationFail
|
|
|
|
|
pure $ All False
|
|
|
|
|
pure $ getAll res
|
|
|
|
|
|