users cannot delete themselves anymore

This commit is contained in:
Steffen Jost 2019-03-22 11:39:59 +01:00
parent 2ddb637b6e
commit 21ba1f2afa
14 changed files with 197 additions and 168 deletions

View File

@ -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:

View File

@ -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
View File

@ -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

View File

@ -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"

View File

@ -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")

View File

@ -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

View File

@ -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.

View File

@ -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}
|])
------------ ------------

View File

@ -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

View File

@ -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

View File

@ -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!

View File

@ -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!

View File

@ -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.

View File

@ -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}