users cannot delete themselves anymore
This commit is contained in:
parent
2ddb637b6e
commit
21ba1f2afa
@ -1,4 +1,5 @@
|
|||||||
Es s
|
Übersicht über PageActions und Workflow im Vergleich zum alten UniWorX:
|
||||||
|
-----
|
||||||
|
|
||||||
Course Actions im alten UniWorX:
|
Course Actions im alten UniWorX:
|
||||||
- Studenten
|
- Studenten
|
||||||
@ -8,6 +9,8 @@ Course Actions im alten UniWorX:
|
|||||||
- E-Mails
|
- E-Mails
|
||||||
- Online-Evaluation
|
- Online-Evaluation
|
||||||
|
|
||||||
|
-----
|
||||||
|
|
||||||
CourseActions in Uni2Work:
|
CourseActions in Uni2Work:
|
||||||
-1 Übungsblätter (öfter)
|
-1 Übungsblätter (öfter)
|
||||||
[ Auch aus SheetList übernommen un hier ebenfalls angzeigt:
|
[ Auch aus SheetList übernommen un hier ebenfalls angzeigt:
|
||||||
|
|||||||
@ -6,6 +6,7 @@ BtnDeregister: Abmelden
|
|||||||
BtnHijack: Sitzung übernehmen
|
BtnHijack: Sitzung übernehmen
|
||||||
|
|
||||||
Aborted: Abgebrochen
|
Aborted: Abgebrochen
|
||||||
|
Remarks: Hinweise
|
||||||
Registered: Angemeldet
|
Registered: Angemeldet
|
||||||
RegisteredHeader: Anmeldung
|
RegisteredHeader: Anmeldung
|
||||||
RegisteredSince date@Text: Angemeldet seit #{date}
|
RegisteredSince date@Text: Angemeldet seit #{date}
|
||||||
|
|||||||
3
routes
3
routes
@ -37,6 +37,7 @@
|
|||||||
/ HomeR GET !free
|
/ HomeR GET !free
|
||||||
/users UsersR GET -- no tags, i.e. admins only
|
/users UsersR GET -- no tags, i.e. admins only
|
||||||
/users/#CryptoUUIDUser AdminUserR GET POST !development
|
/users/#CryptoUUIDUser AdminUserR GET POST !development
|
||||||
|
/users/#CryptoUUIDUser/delete AdminUserDeleteR POST !development
|
||||||
/users/#CryptoUUIDUser/hijack AdminHijackUserR POST !adminANDno-escalation
|
/users/#CryptoUUIDUser/hijack AdminHijackUserR POST !adminANDno-escalation
|
||||||
/admin AdminR GET
|
/admin AdminR GET
|
||||||
/admin/features AdminFeaturesR GET POST
|
/admin/features AdminFeaturesR GET POST
|
||||||
@ -52,7 +53,7 @@
|
|||||||
/help HelpR GET POST !free
|
/help HelpR GET POST !free
|
||||||
|
|
||||||
/user ProfileR GET POST !free
|
/user ProfileR GET POST !free
|
||||||
/user/profile ProfileDataR GET POST !free
|
/user/profile ProfileDataR GET !free
|
||||||
/user/authpreds AuthPredsR GET POST !free
|
/user/authpreds AuthPredsR GET POST !free
|
||||||
|
|
||||||
/term TermShowR GET !free
|
/term TermShowR GET !free
|
||||||
|
|||||||
@ -833,6 +833,7 @@ getCUserR _tid _ssh _csh uCId = do
|
|||||||
-- - User is a lecturer for course
|
-- - User is a lecturer for course
|
||||||
uid <- decrypt uCId
|
uid <- decrypt uCId
|
||||||
User{..} <- runDB $ get404 uid
|
User{..} <- runDB $ get404 uid
|
||||||
|
|
||||||
-- USE src/utils/Form.formResult
|
-- USE src/utils/Form.formResult
|
||||||
defaultLayout -- TODO
|
defaultLayout -- TODO
|
||||||
[whamlet|
|
[whamlet|
|
||||||
@ -844,5 +845,6 @@ getCHiWisR = error "CHiWisR: Not implemented"
|
|||||||
|
|
||||||
getCNotesR, postCNotesR :: TermId -> SchoolId -> CourseShorthand -> Handler Html
|
getCNotesR, postCNotesR :: TermId -> SchoolId -> CourseShorthand -> Handler Html
|
||||||
-- NOTE: The route getNotesR is abused for correctorORlecturer access rights!
|
-- NOTE: The route getNotesR is abused for correctorORlecturer access rights!
|
||||||
getCNotesR = error "CNotesR: Not implemented"
|
-- PROBLEM: Correctors usually don't know Participants by name (anonymous), maybe notes are not shared?
|
||||||
|
getCNotesR = error "CNotesR: Not implemented"
|
||||||
postCNotesR = error "CNotesR: Not implemented"
|
postCNotesR = error "CNotesR: Not implemented"
|
||||||
|
|||||||
@ -121,134 +121,47 @@ postProfileR = do
|
|||||||
setTitle . toHtml $ "Profil " <> userIdent
|
setTitle . toHtml $ "Profil " <> userIdent
|
||||||
$(widgetFile "formPageI18n")
|
$(widgetFile "formPageI18n")
|
||||||
|
|
||||||
postProfileDataR :: Handler Html
|
|
||||||
postProfileDataR = do
|
|
||||||
((btnResult,_), _) <- runFormPost buttonForm
|
|
||||||
case btnResult of
|
|
||||||
(FormSuccess BtnDelete) -> do
|
|
||||||
(uid, User{..}) <- requireAuthPair
|
|
||||||
clearCreds False -- Logout-User
|
|
||||||
((deletedSubmissions,groupSubmissions),deletedSubmissionGroups) <- runDB $ deleteUser uid
|
|
||||||
-- addMessageIHamlet
|
|
||||||
$(addMessageFile Success "templates/deletedUser.hamlet") -- USE THIS ONE
|
|
||||||
-- addMessageI Success $ MsgDeleteUser deletedSubmissions
|
|
||||||
-- when (groupSubmissions > 0) $ addMessageI Info $ MsgDeleteUserGroupSubmissions groupSubmissions
|
|
||||||
defaultLayout
|
|
||||||
$(widgetFile "deletedUser")
|
|
||||||
|
|
||||||
-- (FormSuccess BtnAbort ) -> do
|
|
||||||
-- addMessageI Info MsgAborted
|
|
||||||
-- redirect ProfileDataR
|
|
||||||
_other -> getProfileDataR
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
deleteUser :: UserId -> DB ((Int,Int),Int64) -- TODO: Restrict deletions for lecturers, tutors and students in course that won't allow deregistration
|
|
||||||
deleteUser duid = do
|
|
||||||
-- E.deleteCount for submissions is not cascading, hence we first select and then delete manually
|
|
||||||
-- We delete all files tied to submissions where the user is the lone submissionUser
|
|
||||||
|
|
||||||
-- Do not deleteCascade submissions where duid is the corrector:
|
|
||||||
updateWhere [SubmissionRatingBy ==. Just duid] [SubmissionRatingBy =. Nothing]
|
|
||||||
|
|
||||||
groupSubmissions <- selectSubmissionsWhere (\numBuddies -> numBuddies E.>. E.val (0::Int64))
|
|
||||||
singleSubmissions <- selectSubmissionsWhere (\numBuddies -> numBuddies E.==. E.val (0::Int64))
|
|
||||||
deleteCascade duid
|
|
||||||
forM_ singleSubmissions $ \(E.Value submissionId) -> do
|
|
||||||
deleteFileIds <- map E.unValue <$> getSubmissionFiles submissionId
|
|
||||||
deleteCascade submissionId
|
|
||||||
deleteCascadeWhere [FileId <-. deleteFileIds] -- TODO: throws exception for de-duplicated files
|
|
||||||
|
|
||||||
deletedSubmissionGroups <- deleteSingleSubmissionGroups
|
|
||||||
return ((length singleSubmissions, length groupSubmissions),deletedSubmissionGroups)
|
|
||||||
where
|
|
||||||
selectSubmissionsWhere :: (E.SqlExpr (E.Value Int64) -> E.SqlExpr (E.Value Bool)) -> DB [E.Value (Key Submission)]
|
|
||||||
selectSubmissionsWhere whereBuddies = E.select $ E.from $ \(submission `E.InnerJoin` suser) -> do
|
|
||||||
E.on $ submission E.^. SubmissionId E.==. suser E.^. SubmissionUserSubmission
|
|
||||||
let numBuddies = E.sub_select $ E.from $ \subUsers -> do
|
|
||||||
E.where_ $ subUsers E.^. SubmissionUserSubmission E.==. submission E.^. SubmissionId
|
|
||||||
E.&&. subUsers E.^. SubmissionUserUser E.!=. E.val duid
|
|
||||||
return E.countRows
|
|
||||||
E.where_ $ suser E.^. SubmissionUserUser E.==. E.val duid
|
|
||||||
E.&&. whereBuddies numBuddies
|
|
||||||
return $ submission E.^. SubmissionId
|
|
||||||
|
|
||||||
getSubmissionFiles :: SubmissionId -> DB [E.Value (Key File)]
|
|
||||||
getSubmissionFiles subId = E.select $ E.from $ \file -> do
|
|
||||||
E.where_ $ E.exists $ E.from $ \submissionFile ->
|
|
||||||
E.where_ $ submissionFile E.^. SubmissionFileSubmission E.==. E.val subId
|
|
||||||
E.&&. submissionFile E.^. SubmissionFileFile E.==. file E.^. FileId
|
|
||||||
return $ file E.^. FileId
|
|
||||||
|
|
||||||
deleteSingleSubmissionGroups = E.deleteCount $ E.from $ \submissionGroup -> do
|
|
||||||
E.where_ $ E.exists $ E.from $ \subGroupUser ->
|
|
||||||
E.where_ $ subGroupUser E.^. SubmissionGroupUserSubmissionGroup E.==. submissionGroup E.^. SubmissionGroupId
|
|
||||||
E.&&. subGroupUser E.^. SubmissionGroupUserUser E.==. E.val duid
|
|
||||||
E.where_ $ E.notExists $ E.from $ \subGroupUser ->
|
|
||||||
E.where_ $ subGroupUser E.^. SubmissionGroupUserSubmissionGroup E.==. submissionGroup E.^. SubmissionGroupId
|
|
||||||
E.&&. subGroupUser E.^. SubmissionGroupUserUser E.!=. E.val duid
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
getProfileDataR :: Handler Html
|
getProfileDataR :: Handler Html
|
||||||
getProfileDataR = do
|
getProfileDataR = do
|
||||||
(uid, User{..}) <- requireAuthPair
|
userEnt <- requireAuth
|
||||||
|
dataWidget <- runDB $ makeProfileData userEnt
|
||||||
|
defaultLayout $ do
|
||||||
|
dataWidget
|
||||||
|
$(widgetFile "dsgvDisclaimer")
|
||||||
|
|
||||||
|
makeProfileData :: (Entity User) -> DB Widget
|
||||||
|
makeProfileData (Entity uid User{..}) = do
|
||||||
-- MsgRenderer mr <- getMsgRenderer
|
-- MsgRenderer mr <- getMsgRenderer
|
||||||
(admin_rights,lecturer_rights,lecture_corrector,studies) <- runDB $ (,,,) <$>
|
admin_rights <- E.select $ E.from $ \(adright `E.InnerJoin` school) -> do
|
||||||
E.select
|
E.where_ $ adright E.^. UserAdminUser E.==. E.val uid
|
||||||
( E.from $ \(adright `E.InnerJoin` school) -> do
|
E.on $ adright E.^. UserAdminSchool E.==. school E.^. SchoolId
|
||||||
E.where_ $ adright E.^. UserAdminUser E.==. E.val uid
|
return (school E.^. SchoolShorthand)
|
||||||
E.on $ adright E.^. UserAdminSchool E.==. school E.^. SchoolId
|
lecturer_rights <- E.select $ E.from $ \(lecright `E.InnerJoin` school) -> do
|
||||||
return (school E.^. SchoolShorthand)
|
E.where_ $ lecright E.^. UserLecturerUser E.==. E.val uid
|
||||||
)
|
E.on $ lecright E.^. UserLecturerSchool E.==. school E.^. SchoolId
|
||||||
<*>
|
return (school E.^. SchoolShorthand)
|
||||||
E.select
|
lecture_corrector <- E.select $ E.distinct $ E.from $ \(sheet `E.InnerJoin` corrector `E.InnerJoin` course) -> do
|
||||||
( E.from $ \(lecright `E.InnerJoin` school) -> do
|
E.on $ sheet E.^. SheetCourse E.==. course E.^. CourseId
|
||||||
E.where_ $ lecright E.^. UserLecturerUser E.==. E.val uid
|
E.on $ sheet E.^. SheetId E.==. corrector E.^. SheetCorrectorSheet
|
||||||
E.on $ lecright E.^. UserLecturerSchool E.==. school E.^. SchoolId
|
E.where_ $ corrector E.^. SheetCorrectorUser E.==. E.val uid
|
||||||
return (school E.^. SchoolShorthand)
|
return (course E.^. CourseTerm, course E.^. CourseSchool, course E.^. CourseShorthand)
|
||||||
)
|
studies <- E.select $ E.from $ \(studydegree `E.InnerJoin` studyfeat `E.InnerJoin` studyterms) -> do
|
||||||
<*>
|
E.where_ $ studyfeat E.^. StudyFeaturesUser E.==. E.val uid
|
||||||
E.select
|
E.on $ studyfeat E.^. StudyFeaturesField E.==. studyterms E.^. StudyTermsId
|
||||||
( E.distinct $ E.from $ \(sheet `E.InnerJoin` corrector `E.InnerJoin` course) -> do
|
E.on $ studyfeat E.^. StudyFeaturesDegree E.==. studydegree E.^. StudyDegreeId
|
||||||
E.on $ sheet E.^. SheetCourse E.==. course E.^. CourseId
|
return (studyfeat, studydegree, studyterms)
|
||||||
E.on $ sheet E.^. SheetId E.==. corrector E.^. SheetCorrectorSheet
|
--Tables
|
||||||
E.where_ $ corrector E.^. SheetCorrectorUser E.==. E.val uid
|
(hasRows, ownedCoursesTable) <- mkOwnedCoursesTable uid -- Tabelle mit eigenen Kursen
|
||||||
return (course E.^. CourseTerm, course E.^. CourseSchool, course E.^. CourseShorthand)
|
enrolledCoursesTable <- mkEnrolledCoursesTable uid -- Tabelle mit allen Teilnehmer: Kurs (link), Datum
|
||||||
)
|
submissionTable <- mkSubmissionTable uid -- Tabelle mit allen Abgaben und Abgabe-Gruppen
|
||||||
<*>
|
submissionGroupTable <- mkSubmissionGroupTable uid -- Tabelle mit allen Abgabegruppen
|
||||||
E.select
|
correctionsTable <- mkCorrectionsTable uid -- Tabelle mit allen Korrektor-Aufgaben
|
||||||
( 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)
|
|
||||||
)
|
|
||||||
( (hasRows, ownedCoursesTable)
|
|
||||||
, enrolledCoursesTable
|
|
||||||
, submissionTable
|
|
||||||
, submissionGroupTable
|
|
||||||
, correctionsTable
|
|
||||||
) <- runDB $ (,,,,)
|
|
||||||
<$> mkOwnedCoursesTable uid -- Tabelle mit eigenen Kursen
|
|
||||||
<*> mkEnrolledCoursesTable uid -- Tabelle mit allen Teilnehmer: Kurs (link), Datum
|
|
||||||
<*> mkSubmissionTable uid -- Tabelle mit allen Abgaben und Abgabe-Gruppen
|
|
||||||
<*> mkSubmissionGroupTable uid -- Tabelle mit allen Abgabegruppen
|
|
||||||
<*> mkCorrectionsTable uid -- Tabelle mit allen Korrektor-Aufgaben
|
|
||||||
|
|
||||||
|
|
||||||
let examTable = [whamlet|Klausuren werden momentan leider noch nicht unterstützt.|]
|
let examTable = [whamlet|Klausuren werden momentan leider noch nicht unterstützt.|]
|
||||||
let ownTutorialTable = [whamlet|Übungsgruppen werden momentan leider noch nicht unterstützt.|]
|
let ownTutorialTable = [whamlet|Übungsgruppen werden momentan leider noch nicht unterstützt.|]
|
||||||
let tutorialTable = [whamlet|Übungsgruppen werden momentan leider noch nicht unterstützt.|]
|
let tutorialTable = [whamlet|Übungsgruppen werden momentan leider noch nicht unterstützt.|]
|
||||||
|
|
||||||
lastLogin <- traverse (formatTime SelFormatDateTime) userLastAuthentication
|
lastLogin <- traverse (formatTime SelFormatDateTime) userLastAuthentication
|
||||||
|
return $(widgetFile "profileData")
|
||||||
-- Delete Button
|
|
||||||
(btnWdgt, btnEnctype) <- generateFormPost (buttonForm :: Form ButtonDelete)
|
|
||||||
defaultLayout $ do
|
|
||||||
let delWdgt = $(widgetFile "widgets/data-delete/data-delete")
|
|
||||||
$(widgetFile "profileData")
|
|
||||||
$(widgetFile "dsgvDisclaimer")
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -16,6 +16,8 @@ import qualified Data.Map as Map
|
|||||||
import qualified Database.Esqueleto as E
|
import qualified Database.Esqueleto as E
|
||||||
import qualified Database.Esqueleto.Utils as E
|
import qualified Database.Esqueleto.Utils as E
|
||||||
|
|
||||||
|
import Handler.Profile (makeProfileData)
|
||||||
|
|
||||||
|
|
||||||
hijackUserForm :: CryptoUUIDUser -> Form ()
|
hijackUserForm :: CryptoUUIDUser -> Form ()
|
||||||
hijackUserForm cID csrf = do
|
hijackUserForm cID csrf = do
|
||||||
@ -157,7 +159,7 @@ postAdminUserR uuid = do
|
|||||||
uid <- decrypt uuid
|
uid <- decrypt uuid
|
||||||
let fromSchoolList = Set.fromList . map (userAdminSchool . entityVal)
|
let fromSchoolList = Set.fromList . map (userAdminSchool . entityVal)
|
||||||
let unValueRights (school, E.Value isAdmin, E.Value isLecturer) = (school,isAdmin,isLecturer)
|
let unValueRights (school, E.Value isAdmin, E.Value isLecturer) = (school,isAdmin,isLecturer)
|
||||||
(User{..}, fromSchoolList -> adminSchools, fmap unValueRights -> userRights) <- runDB $ (,,)
|
(user@User{..}, fromSchoolList -> adminSchools, fmap unValueRights -> userRights) <- runDB $ (,,)
|
||||||
<$> get404 uid
|
<$> get404 uid
|
||||||
<*> selectList [UserAdminUser ==. adminId] []
|
<*> selectList [UserAdminUser ==. adminId] []
|
||||||
<*> E.select ( E.from $ \school -> do
|
<*> E.select ( E.from $ \school -> do
|
||||||
@ -172,7 +174,7 @@ postAdminUserR uuid = do
|
|||||||
)
|
)
|
||||||
-- above data is needed for both form generation and result evaluation
|
-- above data is needed for both form generation and result evaluation
|
||||||
let userRightsForm :: Form [(SchoolId, Bool, Bool)]
|
let userRightsForm :: Form [(SchoolId, Bool, Bool)]
|
||||||
userRightsForm csrf = do
|
userRightsForm = identifyForm FIDuserRights $ \csrf -> do
|
||||||
boxRights <- forM userRights $ \(school@(Entity sid _), isAdmin, isLecturer) ->
|
boxRights <- forM userRights $ \(school@(Entity sid _), isAdmin, isLecturer) ->
|
||||||
if Set.member sid adminSchools
|
if Set.member sid adminSchools
|
||||||
then do
|
then do
|
||||||
@ -205,5 +207,79 @@ postAdminUserR uuid = do
|
|||||||
formResult result userRightsAction
|
formResult result userRightsAction
|
||||||
let heading =
|
let heading =
|
||||||
[whamlet|_{MsgAccessRightsFor} ^{nameWidget userDisplayName userSurname}|]
|
[whamlet|_{MsgAccessRightsFor} ^{nameWidget userDisplayName userSurname}|]
|
||||||
siteLayout heading
|
-- Delete Button needed in data-delete
|
||||||
|
(btnWdgt, btnEnctype) <- generateFormPost (buttonForm :: Form ButtonDelete)
|
||||||
|
userDataWidget <- runDB $ makeProfileData $ Entity uid user
|
||||||
|
siteLayout heading $ do
|
||||||
|
let deleteWidget = $(widgetFile "widgets/data-delete/data-delete")
|
||||||
$(widgetFile "adminUser")
|
$(widgetFile "adminUser")
|
||||||
|
|
||||||
|
|
||||||
|
postAdminUserDeleteR :: CryptoUUIDUser -> Handler Html
|
||||||
|
postAdminUserDeleteR uuid = do
|
||||||
|
uid <- decrypt uuid
|
||||||
|
((btnResult,_), _) <- runFormPost (buttonForm :: Form ButtonDelete)
|
||||||
|
case btnResult of
|
||||||
|
(FormSuccess BtnDelete) -> do
|
||||||
|
User{..} <- runDB $ get404 uid
|
||||||
|
-- clearCreds False -- Logout-User
|
||||||
|
((deletedSubmissions,groupSubmissions),deletedSubmissionGroups) <- runDB $ deleteUser uid
|
||||||
|
-- addMessageIHamlet
|
||||||
|
$(addMessageFile Success "templates/deletedUser.hamlet") -- USE THIS ONE
|
||||||
|
-- addMessageI Success $ MsgDeleteUser deletedSubmissions
|
||||||
|
-- when (groupSubmissions > 0) $ addMessageI Info $ MsgDeleteUserGroupSubmissions groupSubmissions
|
||||||
|
defaultLayout
|
||||||
|
$(widgetFile "deletedUser")
|
||||||
|
|
||||||
|
-- (FormSuccess BtnAbort ) -> do
|
||||||
|
-- addMessageI Info MsgAborted
|
||||||
|
-- redirect ProfileDataR
|
||||||
|
_other -> getAdminUserR uuid
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
deleteUser :: UserId -> DB ((Int,Int),Int64) -- TODO: Restrict deletions for lecturers, tutors and students in course that won't allow deregistration
|
||||||
|
deleteUser duid = do
|
||||||
|
-- E.deleteCount for submissions is not cascading, hence we first select and then delete manually
|
||||||
|
-- We delete all files tied to submissions where the user is the lone submissionUser
|
||||||
|
|
||||||
|
-- Do not deleteCascade submissions where duid is the corrector:
|
||||||
|
updateWhere [SubmissionRatingBy ==. Just duid] [SubmissionRatingBy =. Nothing]
|
||||||
|
|
||||||
|
groupSubmissions <- selectSubmissionsWhere (\numBuddies -> numBuddies E.>. E.val (0::Int64))
|
||||||
|
singleSubmissions <- selectSubmissionsWhere (\numBuddies -> numBuddies E.==. E.val (0::Int64))
|
||||||
|
deleteCascade duid
|
||||||
|
forM_ singleSubmissions $ \(E.Value submissionId) -> do
|
||||||
|
deleteFileIds <- map E.unValue <$> getSubmissionFiles submissionId
|
||||||
|
deleteCascade submissionId
|
||||||
|
deleteCascadeWhere [FileId <-. deleteFileIds] -- TODO: throws exception for de-duplicated files
|
||||||
|
|
||||||
|
deletedSubmissionGroups <- deleteSingleSubmissionGroups
|
||||||
|
return ((length singleSubmissions, length groupSubmissions),deletedSubmissionGroups)
|
||||||
|
where
|
||||||
|
selectSubmissionsWhere :: (E.SqlExpr (E.Value Int64) -> E.SqlExpr (E.Value Bool)) -> DB [E.Value (Key Submission)]
|
||||||
|
selectSubmissionsWhere whereBuddies = E.select $ E.from $ \(submission `E.InnerJoin` suser) -> do
|
||||||
|
E.on $ submission E.^. SubmissionId E.==. suser E.^. SubmissionUserSubmission
|
||||||
|
let numBuddies = E.sub_select $ E.from $ \subUsers -> do
|
||||||
|
E.where_ $ subUsers E.^. SubmissionUserSubmission E.==. submission E.^. SubmissionId
|
||||||
|
E.&&. subUsers E.^. SubmissionUserUser E.!=. E.val duid
|
||||||
|
return E.countRows
|
||||||
|
E.where_ $ suser E.^. SubmissionUserUser E.==. E.val duid
|
||||||
|
E.&&. whereBuddies numBuddies
|
||||||
|
return $ submission E.^. SubmissionId
|
||||||
|
|
||||||
|
getSubmissionFiles :: SubmissionId -> DB [E.Value (Key File)]
|
||||||
|
getSubmissionFiles subId = E.select $ E.from $ \file -> do
|
||||||
|
E.where_ $ E.exists $ E.from $ \submissionFile ->
|
||||||
|
E.where_ $ submissionFile E.^. SubmissionFileSubmission E.==. E.val subId
|
||||||
|
E.&&. submissionFile E.^. SubmissionFileFile E.==. file E.^. FileId
|
||||||
|
return $ file E.^. FileId
|
||||||
|
|
||||||
|
deleteSingleSubmissionGroups = E.deleteCount $ E.from $ \submissionGroup -> do
|
||||||
|
E.where_ $ E.exists $ E.from $ \subGroupUser ->
|
||||||
|
E.where_ $ subGroupUser E.^. SubmissionGroupUserSubmissionGroup E.==. submissionGroup E.^. SubmissionGroupId
|
||||||
|
E.&&. subGroupUser E.^. SubmissionGroupUserUser E.==. E.val duid
|
||||||
|
E.where_ $ E.notExists $ E.from $ \subGroupUser ->
|
||||||
|
E.where_ $ subGroupUser E.^. SubmissionGroupUserSubmissionGroup E.==. submissionGroup E.^. SubmissionGroupId
|
||||||
|
E.&&. subGroupUser E.^. SubmissionGroupUserUser E.!=. E.val duid
|
||||||
|
|
||||||
|
|||||||
@ -44,11 +44,16 @@ simpleLink :: Widget -> Route UniWorX -> Widget
|
|||||||
simpleLink lbl url = [whamlet|<a href=@{url}>^{lbl}|]
|
simpleLink lbl url = [whamlet|<a href=@{url}>^{lbl}|]
|
||||||
|
|
||||||
-- | toWidget-Version of @nameHtml@, for convenience
|
-- | toWidget-Version of @nameHtml@, for convenience
|
||||||
nameWidget :: Text -> Text -> Widget
|
nameWidget :: Text -- ^ userDisplayName
|
||||||
|
-> Text -- ^ userSurname
|
||||||
|
-> Widget
|
||||||
nameWidget displayName surname = toWidget $ nameHtml displayName surname
|
nameWidget displayName surname = toWidget $ nameHtml displayName surname
|
||||||
|
|
||||||
-- | toWidget-Version of @nameEmailHtml@, for convenience
|
-- | toWidget-Version of @nameEmailHtml@, for convenience
|
||||||
nameEmailWidget :: CI Text -> Text -> Text -> Widget
|
nameEmailWidget :: CI Text -- ^ userEmail
|
||||||
|
-> Text -- ^ userDisplayName
|
||||||
|
-> Text -- ^ userSurname
|
||||||
|
-> Widget
|
||||||
nameEmailWidget email displayName surname = toWidget $ nameEmailHtml email displayName surname
|
nameEmailWidget email displayName surname = toWidget $ nameEmailHtml email displayName surname
|
||||||
|
|
||||||
-- | Show user's displayName, highlighting the surname if possible.
|
-- | Show user's displayName, highlighting the surname if possible.
|
||||||
|
|||||||
@ -125,14 +125,16 @@ linkButton lbl cls url = do
|
|||||||
|
|
||||||
-- buttonForm :: (Button UniWorX a, Finite a) => Markup -> MForm (HandlerT UniWorX IO) (FormResult a, Widget)
|
-- buttonForm :: (Button UniWorX a, Finite a) => Markup -> MForm (HandlerT UniWorX IO) (FormResult a, Widget)
|
||||||
buttonForm :: (Button UniWorX a, Finite a) => Form a
|
buttonForm :: (Button UniWorX a, Finite a) => Form a
|
||||||
buttonForm csrf = do
|
buttonForm = identifyForm FIDbuttonForm buttonFormAux -- TODO: distinguish diffent buttons despite @disambiguateButtons@
|
||||||
(res, ($ []) -> fViews) <- aFormToForm . disambiguateButtons $ combinedButtonFieldF ""
|
where
|
||||||
return (res, [whamlet|
|
buttonFormAux csrf = do
|
||||||
$newline never
|
(res, ($ []) -> fViews) <- aFormToForm . disambiguateButtons $ combinedButtonFieldF ""
|
||||||
#{csrf}
|
return (res, [whamlet|
|
||||||
$forall bView <- fViews
|
$newline never
|
||||||
^{fvInput bView}
|
#{csrf}
|
||||||
|])
|
$forall bView <- fViews
|
||||||
|
^{fvInput bView}
|
||||||
|
|])
|
||||||
|
|
||||||
|
|
||||||
------------
|
------------
|
||||||
|
|||||||
@ -4,7 +4,11 @@ import Data.Either (isLeft)
|
|||||||
|
|
||||||
import Import.NoFoundation
|
import Import.NoFoundation
|
||||||
|
|
||||||
modal :: WidgetT site IO () -> Either (SomeRoute site) (WidgetT site IO ()) -> WidgetT site IO ()
|
|
||||||
|
-- | Create a link to a modal
|
||||||
|
modal :: WidgetT site IO () -- ^ Widget that represents the link
|
||||||
|
-> Either (SomeRoute site) (WidgetT site IO ()) -- ^ Modal contant: either dynamic link or static widget
|
||||||
|
-> WidgetT site IO () -- ^ result widget
|
||||||
modal modalTrigger modalContent = do
|
modal modalTrigger modalContent = do
|
||||||
let modalDynamic = isLeft modalContent
|
let modalDynamic = isLeft modalContent
|
||||||
modalId <- newIdent
|
modalId <- newIdent
|
||||||
|
|||||||
@ -217,6 +217,8 @@ data FormIdentifier
|
|||||||
| FIDDBTable
|
| FIDDBTable
|
||||||
| FIDDelete
|
| FIDDelete
|
||||||
| FIDCourseRegister
|
| FIDCourseRegister
|
||||||
|
| FIDuserRights
|
||||||
|
| FIDbuttonForm
|
||||||
deriving (Eq, Ord, Read, Show)
|
deriving (Eq, Ord, Read, Show)
|
||||||
|
|
||||||
instance PathPiece FormIdentifier where
|
instance PathPiece FormIdentifier where
|
||||||
@ -238,7 +240,7 @@ identifyForm' resLens identVal form fragment = do
|
|||||||
|]
|
|]
|
||||||
|
|
||||||
-- Check if we got its value back.
|
-- Check if we got its value back.
|
||||||
hasIdent <- (== Just identVal) <$> lookupGlobalPostParamForm PostFormIdentifier
|
hasIdent <- (== Just identVal) <$> lookupGlobalPostParamForm PostFormIdentifier
|
||||||
|
|
||||||
-- Run the form proper (with our hidden <input>). If the
|
-- Run the form proper (with our hidden <input>). If the
|
||||||
-- data is missing, then do not provide any params to the
|
-- data is missing, then do not provide any params to the
|
||||||
@ -250,7 +252,7 @@ identifyForm' resLens identVal form fragment = do
|
|||||||
|
|
||||||
identifyForm :: (Monad m, PathPiece ident, Eq ident) => ident -> (Html -> MForm m (FormResult a, widget)) -> (Html -> MForm m (FormResult a, widget))
|
identifyForm :: (Monad m, PathPiece ident, Eq ident) => ident -> (Html -> MForm m (FormResult a, widget)) -> (Html -> MForm m (FormResult a, widget))
|
||||||
identifyForm = identifyForm' id
|
identifyForm = identifyForm' id
|
||||||
|
|
||||||
|
|
||||||
{- Hinweise zur Erinnerung:
|
{- Hinweise zur Erinnerung:
|
||||||
- identForm primär, wenn es mehr als ein Formular pro Handler gibt
|
- identForm primär, wenn es mehr als ein Formular pro Handler gibt
|
||||||
|
|||||||
@ -1,6 +1,14 @@
|
|||||||
<p>
|
<section>
|
||||||
$# Does not use link-email.hamlet, but should
|
$# Does not use link-email.hamlet, but should
|
||||||
^{mailtoHtml userEmail}
|
^{mailtoHtml userEmail}
|
||||||
<form method=post action=@{AdminUserR uuid} enctype=#{formEnctype}>
|
<form method=post action=@{AdminUserR uuid} enctype=#{formEnctype}>
|
||||||
^{formWidget}
|
^{formWidget}
|
||||||
^{submitButtonView}
|
^{submitButtonView}
|
||||||
|
<section>
|
||||||
|
^{userDataWidget}
|
||||||
|
<h3>
|
||||||
|
^{modal "Benutzer löschen" (Right deleteWidget)}
|
||||||
|
Achtung, dieser Link löscht momentan noch den kompletten Benutzer
|
||||||
|
unwiderruflich aus der Live-Datenbank mit
|
||||||
|
<code>DELETE CASCADE uid
|
||||||
|
\ Klausurdaten müssen jedoch langfristig gespeichert werden!
|
||||||
@ -1,6 +1,10 @@
|
|||||||
<div .container>
|
<div .container>
|
||||||
<h1>
|
<h1>
|
||||||
_{MsgUserAccountDeleted userDisplayName}
|
_{MsgUserAccountDeleted userDisplayName}
|
||||||
|
<div .container>
|
||||||
|
#{nameEmailHtml userEmail userDisplayName userSurname}
|
||||||
|
<div .container>
|
||||||
|
#{mailtoHtml userEmail}
|
||||||
<div .container>
|
<div .container>
|
||||||
#{display deletedSubmissions} Abgaben wurden unwiederruflich gelöscht.
|
#{display deletedSubmissions} Abgaben wurden unwiederruflich gelöscht.
|
||||||
$if groupSubmissions > 0
|
$if groupSubmissions > 0
|
||||||
@ -12,5 +16,3 @@
|
|||||||
$if deletedSubmissionGroups > 0
|
$if deletedSubmissionGroups > 0
|
||||||
<div .container>
|
<div .container>
|
||||||
#{display deletedSubmissionGroups} benannte Abgabengruppen wurden gelöscht, da diese dadurch leer wurden.
|
#{display deletedSubmissionGroups} benannte Abgabengruppen wurden gelöscht, da diese dadurch leer wurden.
|
||||||
<div .container>
|
|
||||||
Good Bye!
|
|
||||||
|
|||||||
@ -115,20 +115,28 @@
|
|||||||
<a href=@{CorrectionsR}>Auflistung aller tatsächlich zugewiesenen Korrekturen
|
<a href=@{CorrectionsR}>Auflistung aller tatsächlich zugewiesenen Korrekturen
|
||||||
.
|
.
|
||||||
|
|
||||||
<h2>
|
|
||||||
^{modal "Alle Benutzerbezogenen Daten löschen" (Right delWdgt)}
|
<section>
|
||||||
<p>
|
<h2>_{MsgRemarks}
|
||||||
<h4>Hinweise:
|
|
||||||
<ul>
|
<ul>
|
||||||
<li>
|
<li>
|
||||||
Sichern Sie Ihre Daten! Während des Testbetriebs von Uni2work
|
Sichern Sie bitte Ihre Daten! Die Uni2work Datenbank wird täglich gesichert;
|
||||||
könnten Daten unabsichtlich unwidderuflich gelöscht werden.
|
dennoch können wir Probleme während des Testbetriebs noch nicht gänzlich ausschließen.
|
||||||
<li>
|
<li>
|
||||||
Nicht aufgeführt sind Zeitstempel mit Benutzerinformationen, z.B. bei der Editierung und Korrektur von Übungen, Übungsgruppenleiterschaft, Raumbuchungen, etc.
|
Nicht aufgeführt sind Zeitstempel mit Benutzerinformationen, z.B. bei der Editierung und Korrektur von Übungen, Übungsgruppenleiterschaft, Raumbuchungen, etc.
|
||||||
<li>
|
<li>
|
||||||
Benutzerdaten bleiben so lange gespeichert, bis ein Institutsadministrator über die Exmatrikulation informiert wurde. Dann wird der Account gelöscht.
|
Sie können die
|
||||||
Abgaben/Bonuspunkte werden unwiderruflich gelöscht.
|
<a href=@{HelpR}>
|
||||||
Klausurnoten verbleiben aus statistischen Gründen anonymisiert im System.
|
Löschung Ihre Daten über eine Supportanfrage beantragen
|
||||||
|
. Ihre Daten werden dann nach Ablauf einer Frist gelöscht.
|
||||||
|
Daten, welche keiner gesetzlichen Aufbewahrungsfrist unterliegen
|
||||||
|
(z.B. Klausurnoten) verbleiben im System bis zur Ablauf der Aufbewahrungsfrist.
|
||||||
|
<p>
|
||||||
|
Benutzerdaten bleiben prinzipiell so lange gespeichert,
|
||||||
|
bis ein Institutsadministrator über die Exmatrikulation informiert wurde.
|
||||||
|
Dann wird der Account mit einer angemessenen zeitverzögerung gelöscht.
|
||||||
|
Anonymisierte Klausurnoten verbleiben aus statistischen Gründen dauerhaft im System.
|
||||||
|
|
||||||
<li>
|
<li>
|
||||||
Bei gemeinsamen Gruppenabgaben wird nur die Zuordnung zu diesem Benutzer gelöscht.
|
Bei gemeinsamen Gruppenabgaben wird nur die Zuordnung zu diesem Benutzer gelöscht.
|
||||||
Die Abgabe selbst wird erst gelöscht, wenn alle Benutzer einer Abgabe deren Löschung veranlasst haben.
|
Die Abgabe selbst wird erst gelöscht, wenn alle Benutzer einer Abgabe deren Löschung veranlasst haben.
|
||||||
|
|||||||
@ -1,16 +1,22 @@
|
|||||||
<form .form-inline method=post action=@{ProfileDataR} enctype=#{btnEnctype}>
|
<form .form-inline method=post action=@{AdminUserDeleteR uuid} enctype=#{btnEnctype}>
|
||||||
<h2>
|
<h2>
|
||||||
Sind Sie sich absolut sicher, alle Ihre in Uni2work gespeicherten Daten zu löschen?
|
Sind Sie sich absolut sicher
|
||||||
|
Benutzer ^{nameEmailWidget userEmail userDisplayName userSurname} zu löschen?
|
||||||
<div .container>
|
<div .container>
|
||||||
Während der Testphase von Uni2work können Sie hiermit
|
Während der Testphase von Uni2work
|
||||||
Ihren Account bei Uni2work vollständig löschen.
|
werden Benutzer hiermit vollständig aus der Live-Datenbank mit
|
||||||
Mit Ihrem Campus-Account können Sie sich aber danach
|
<code>DELETE CASCADE uid
|
||||||
jederzeit erneut einloggen, wodurch wieder ein leerer Account erstellt wird.
|
gelöscht.
|
||||||
|
Klausurdaten müssen jedoch unbedingt 5 Jahre bis nach Exmatrikulation
|
||||||
|
aufbewahrt werden!
|
||||||
|
<div .container>
|
||||||
|
Benutzer können sich mit Ihrem Campus-Account
|
||||||
|
natürlich jederzeit erneut einloggen, wodurch wieder ein leerer Account erstellt wird.
|
||||||
<div .container>
|
<div .container>
|
||||||
Hochgeladene Hausaufgaben-Dateien werden unabhhängig vom Urherber nur dann gelöscht,
|
Hochgeladene Hausaufgaben-Dateien werden unabhhängig vom Urherber nur dann gelöscht,
|
||||||
wenn die Dateien ausschließlich Ihnen zugeordnet sind.
|
wenn die Dateien ausschließlich diesem Benutzer zugeordnet waren.
|
||||||
Dateien aus Gruppenabgaben werden also erst dann gelöscht,
|
Dateien aus Gruppenabgaben werden also erst dann gelöscht,
|
||||||
wenn alle Gruppenmitglieder Ihren Account gelöscht haben.
|
wenn die Accounts alle Gruppenmitglieder gelöscht wurden.
|
||||||
<div .container>
|
<div .container>
|
||||||
<em>Achtung:
|
<em>Achtung:
|
||||||
Auch abgegebene Hausübungen werden gelöscht!
|
Auch abgegebene Hausübungen werden gelöscht!
|
||||||
@ -19,9 +25,5 @@
|
|||||||
(Verbuchte Noten sollten dadurch nicht betroffen sein, aber in einem etwaigen
|
(Verbuchte Noten sollten dadurch nicht betroffen sein, aber in einem etwaigen
|
||||||
Streitfall konnen die per Uni2work verwalteten Hausaufgaben dann
|
Streitfall konnen die per Uni2work verwalteten Hausaufgaben dann
|
||||||
auch nicht mehr rekonstruiert/berücksichtigt werden.)
|
auch nicht mehr rekonstruiert/berücksichtigt werden.)
|
||||||
<div .container>
|
|
||||||
<em>Nach der Testphase von Uni2work wird das Löschen eines Accounts etwas
|
|
||||||
eingeschränkt werden, da z.B. Klausurnoten 5 Jahre bis nach Exmatrikulation
|
|
||||||
aufbewahrt werden müssen.
|
|
||||||
<div .container>
|
<div .container>
|
||||||
^{btnWdgt}
|
^{btnWdgt}
|
||||||
|
|||||||
Reference in New Issue
Block a user