fix(users): assimilate merges possibly incomplete user fields

This commit is contained in:
Steffen Jost 2023-04-25 16:08:22 +00:00
parent d973acf42b
commit 52afd13b6d
4 changed files with 44 additions and 14 deletions

View File

@ -22,7 +22,7 @@ AdminUserPostAddress: Postalische Anschrift
AdminUserPrefersPostal: Briefe anstatt Email bevorzugt AdminUserPrefersPostal: Briefe anstatt Email bevorzugt
AdminUserPinPassword: Passwort zur Verschlüsselung von PDF Anhängen in Emails AdminUserPinPassword: Passwort zur Verschlüsselung von PDF Anhängen in Emails
AdminUserNoPassword: Kein Passwort gesetzt AdminUserNoPassword: Kein Passwort gesetzt
AdminUserAssimilate: Benutzer assimilieren AdminUserAssimilate: Diesen Benutzer assimilieren von
UserAdded: Benutzer erfolgreich angelegt UserAdded: Benutzer erfolgreich angelegt
UserCollision: Benutzer konnte wegen Eindeutigkeit nicht angelegt werden UserCollision: Benutzer konnte wegen Eindeutigkeit nicht angelegt werden
HeadingUserAdd: Benutzer:in anlegen HeadingUserAdd: Benutzer:in anlegen

View File

@ -22,7 +22,7 @@ AdminUserPostAddress: Postal Address
AdminUserPrefersPostal: Prefers postal letters over email AdminUserPrefersPostal: Prefers postal letters over email
AdminUserPinPassword: Password used for PDF attachments to emails AdminUserPinPassword: Password used for PDF attachments to emails
AdminUserNoPassword: No password set AdminUserNoPassword: No password set
AdminUserAssimilate: Assimilate user AdminUserAssimilate: Assimilate user by another user
UserAdded: Successfully added user UserAdded: Successfully added user
UserCollision: Could not create user due to uniqueness constraint UserCollision: Could not create user due to uniqueness constraint
HeadingUserAdd: Add user HeadingUserAdd: Add user

View File

@ -564,7 +564,7 @@ postAdminUserR uuid = do
let assimilateForm' = renderAForm FormStandard $ let assimilateForm' = renderAForm FormStandard $
areq (checkMap (first $ const MsgAssimilateUserNotFound) Right $ userField False Nothing) (fslI MsgUserAssimilateUser) Nothing areq (checkMap (first $ const MsgAssimilateUserNotFound) Right $ userField False Nothing) (fslI MsgUserAssimilateUser) Nothing
assimilateAction oldUserId = do assimilateAction oldUserId = do
res <- try . runDB . setSerializable $ assimilateUser uid oldUserId res <- try . runDB . setSerializable $ assimilateUser oldUserId uid
case res of case res of
Left (err :: UserAssimilateException) -> Left (err :: UserAssimilateException) ->
addMessageModal Error (i18n MsgAssimilateUserHaveError) $ Right addMessageModal Error (i18n MsgAssimilateUserHaveError) $ Right

View File

@ -34,7 +34,7 @@ import qualified Data.Aeson as JSON
import qualified Data.Aeson.Types as JSON import qualified Data.Aeson.Types as JSON
import qualified Data.Set as Set import qualified Data.Set as Set
import qualified Data.List as List -- import qualified Data.List as List
import qualified Data.CaseInsensitive as CI import qualified Data.CaseInsensitive as CI
import qualified Database.Esqueleto.Legacy as E import qualified Database.Esqueleto.Legacy as E
@ -287,6 +287,16 @@ assimilateUser :: UserId -- ^ @newUserId@
-- --
-- Fatal errors are thrown, non-fatal warnings are returned -- Fatal errors are thrown, non-fatal warnings are returned
assimilateUser newUserId oldUserId = mapReaderT execWriterT $ do assimilateUser newUserId oldUserId = mapReaderT execWriterT $ do
-- retrieve user entities first, to ensure they both exist
(oldUserEnt, newUserEnt) <- do
oldUser <- getEntity oldUserId
newUser <- getEntity newUserId
case (oldUser, newUser) of
(Just old, Just new) -> return (old,new)
_ -> tellError UserAssimilateCouldNotDetermineUserIdents
let oldUser = oldUserEnt ^. _entityVal
newUser = newUserEnt ^. _entityVal
E.insertSelectWithConflict E.insertSelectWithConflict
UniqueCourseFavourite UniqueCourseFavourite
(E.from $ \courseFavourite -> do (E.from $ \courseFavourite -> do
@ -859,18 +869,38 @@ assimilateUser newUserId oldUserId = mapReaderT execWriterT $ do
(\current _excluded -> [ UserCompanySupervisor E.=. (current E.^. UserCompanySupervisor)] ) (\current _excluded -> [ UserCompanySupervisor E.=. (current E.^. UserCompanySupervisor)] )
deleteWhere [ UserCompanyUser ==. oldUserId] deleteWhere [ UserCompanyUser ==. oldUserId]
userIdents <- E.select . E.from $ \user -> do -- merge some optional / incomplete user fields
E.where_ $ user E.^. UserId `E.in_` E.valList [newUserId, oldUserId] update newUserId [upd | (True, upd) <- -- NOTE: persist does shortcircuit null updates as expected
return ( user E.^. UserId [ ( isNothing (newUser ^. _userLdapPrimaryKey) && isJust (oldUser ^. _userLdapPrimaryKey)
, user E.^. UserIdent , UserLdapPrimaryKey =. oldUser ^. _userLdapPrimaryKey )
) , ( newUser ^. _userAuthentication > oldUser ^. _userAuthentication
case (,) <$> List.lookup (E.Value oldUserId) userIdents <*> List.lookup (E.Value newUserId) userIdents of , UserAuthentication =. oldUser ^. _userAuthentication )
Just (E.Value oldIdent, E.Value newIdent') , ( newUser ^. _userLastAuthentication < oldUser ^. _userLastAuthentication
| oldIdent /= newIdent' -> audit $ TransactionUserIdentChanged oldIdent newIdent' , UserLastAuthentication =. oldUser ^. _userLastAuthentication )
| otherwise -> return () , ( newUser ^. _userCreated > oldUser ^. _userCreated
_other -> tellError UserAssimilateCouldNotDetermineUserIdents , UserCreated =. oldUser ^. _userCreated )
, ( not (validEmail' (newUser ^. _userEmail )) && validEmail' (oldUser ^. _userEmail)
, UserEmail =. oldUser ^. _userEmail)
, ( not (validEmail' (newUser ^. _userDisplayEmail)) && validEmail' (oldUser ^. _userDisplayEmail)
, UserDisplayEmail =. oldUser ^. _userDisplayEmail)
, ( isNothing (newUser ^. _userMatrikelnummer) && isJust (oldUser ^. _userMatrikelnummer)
, UserMatrikelnummer =. oldUser ^. _userMatrikelnummer )
, ( isNothing (newUser ^. _userPostAddress) && isJust (oldUser ^. _userPostAddress)
, UserPostAddress =. oldUser ^. _userPostAddress )
, ( isNothing (newUser ^. _userPostAddress) && isJust (oldUser ^. _userPostAddress)
, UserPostLastUpdate =. oldUser ^. _userPostLastUpdate )
, ( (isJust (newUser ^. _userPostAddress) || isJust (oldUser ^. _userPostAddress))
&& (newUser ^. _userPrefersPostal || oldUser ^. _userPrefersPostal)
, UserPrefersPostal =. True )
, ( isNothing (newUser ^. _userPinPassword) && isJust (oldUser ^. _userPinPassword)
, UserPinPassword =. oldUser ^. _userPinPassword )
]
]
delete oldUserId delete oldUserId
let oldUsrIdent = oldUser ^. _userIdent
newUsrIdent = newUser ^. _userIdent
when (oldUsrIdent /= newUsrIdent) $ audit $ TransactionUserIdentChanged oldUsrIdent newUsrIdent
audit $ TransactionUserAssimilated newUserId oldUserId audit $ TransactionUserAssimilated newUserId oldUserId
where where
tellWarning :: UserAssimilateExceptionReason -> ReaderT SqlBackend (WriterT (Set UserAssimilateException) Handler) () tellWarning :: UserAssimilateExceptionReason -> ReaderT SqlBackend (WriterT (Set UserAssimilateException) Handler) ()