chore(avs): upsert avs user continued (WIP)
This commit is contained in:
parent
6f7282b512
commit
453bbd6ce4
@ -14,7 +14,7 @@ import Import.NoFoundation
|
|||||||
data UpsertCampusUserMode
|
data UpsertCampusUserMode
|
||||||
= UpsertCampusUserLoginLdap
|
= UpsertCampusUserLoginLdap
|
||||||
| UpsertCampusUserLoginDummy { upsertCampusUserIdent :: UserIdent }
|
| UpsertCampusUserLoginDummy { upsertCampusUserIdent :: UserIdent }
|
||||||
| UpsertCampusUserLoginOther { upsertCampusUserIdent :: UserIdent }
|
| UpsertCampusUserLoginOther { upsertCampusUserIdent :: UserIdent } -- erlaubt keinen späteren Login
|
||||||
| UpsertCampusUserLdapSync { upsertCampusUserIdent :: UserIdent }
|
| UpsertCampusUserLdapSync { upsertCampusUserIdent :: UserIdent }
|
||||||
| UpsertCampusUserGuessUser
|
| UpsertCampusUserGuessUser
|
||||||
deriving (Eq, Ord, Read, Show, Generic, Typeable)
|
deriving (Eq, Ord, Read, Show, Generic, Typeable)
|
||||||
|
|||||||
@ -4,8 +4,9 @@
|
|||||||
|
|
||||||
module Handler.Users.Add
|
module Handler.Users.Add
|
||||||
( getAdminUserAddR, postAdminUserAddR
|
( getAdminUserAddR, postAdminUserAddR
|
||||||
, AdminUserForm(..), adminUserForm -- no longer needed elsewhere
|
, AdminUserForm(..), AuthenticationKind(..)
|
||||||
-- , AuthenticationKind(..), classifyAuth, mkAuthMode -- no longer needed elsewhere
|
, addNewUser
|
||||||
|
--, adminUserForm , classifyAuth, mkAuthMode -- no longer needed elsewhere
|
||||||
) where
|
) where
|
||||||
|
|
||||||
|
|
||||||
@ -74,66 +75,64 @@ adminUserForm template = renderAForm FormStandard
|
|||||||
<*> areq (textField & cfStrip & cfCI) (fslI MsgAdminUserIdent) (aufIdent <$> template)
|
<*> areq (textField & cfStrip & cfCI) (fslI MsgAdminUserIdent) (aufIdent <$> template)
|
||||||
<*> areq (selectField optionsFinite) (fslI MsgAdminUserAuth) (aufAuth <$> template <|> Just AuthKindLDAP)
|
<*> areq (selectField optionsFinite) (fslI MsgAdminUserAuth) (aufAuth <$> template <|> Just AuthKindLDAP)
|
||||||
|
|
||||||
|
addNewUser :: AdminUserForm -> Handler (Maybe UserId)
|
||||||
|
addNewUser AdminUserForm{..} = do
|
||||||
|
now <- liftIO getCurrentTime
|
||||||
|
UserDefaultConf{..} <- getsYesod $ view _appUserDefaults
|
||||||
|
let
|
||||||
|
newUser = User
|
||||||
|
{ userIdent = aufIdent
|
||||||
|
, userMaxFavourites = userDefaultMaxFavourites
|
||||||
|
, userMaxFavouriteTerms = userDefaultMaxFavouriteTerms
|
||||||
|
, userTheme = userDefaultTheme
|
||||||
|
, userDateTimeFormat = userDefaultDateTimeFormat
|
||||||
|
, userDateFormat = userDefaultDateFormat
|
||||||
|
, userTimeFormat = userDefaultTimeFormat
|
||||||
|
, userDownloadFiles = userDefaultDownloadFiles
|
||||||
|
, userWarningDays = userDefaultWarningDays
|
||||||
|
, userShowSex = userDefaultShowSex
|
||||||
|
, userExamOfficeGetSynced = userDefaultExamOfficeGetSynced
|
||||||
|
, userExamOfficeGetLabels = userDefaultExamOfficeGetLabels
|
||||||
|
, userNotificationSettings = def
|
||||||
|
, userLanguages = Nothing
|
||||||
|
, userCsvOptions = def
|
||||||
|
, userTokensIssuedAfter = Nothing
|
||||||
|
, userCreated = now
|
||||||
|
, userLastLdapSynchronisation = Nothing
|
||||||
|
, userLdapPrimaryKey = aufFPersonalNumber
|
||||||
|
, userLastAuthentication = Nothing
|
||||||
|
, userEmail = aufEmail
|
||||||
|
, userDisplayName = aufDisplayName
|
||||||
|
, userDisplayEmail = aufDisplayEmail
|
||||||
|
, userFirstName = aufFirstName
|
||||||
|
, userSurname = aufSurname
|
||||||
|
, userTitle = aufTitle
|
||||||
|
, userSex = aufSex
|
||||||
|
, userMobile = aufMobile
|
||||||
|
, userTelephone = aufTelephone
|
||||||
|
, userCompanyPersonalNumber = aufFPersonalNumber
|
||||||
|
, userCompanyDepartment = aufFDepartment
|
||||||
|
, userPostAddress = aufPostAddress
|
||||||
|
, userPrefersPostal = aufPrefersPostal
|
||||||
|
, userPinPassword = aufPinPassword
|
||||||
|
, userMatrikelnummer = aufMatriculation
|
||||||
|
, userAuthentication = mkAuthMode aufAuth
|
||||||
|
}
|
||||||
|
runDBJobs . runMaybeT $ do
|
||||||
|
uid <- MaybeT $ insertUnique newUser
|
||||||
|
lift . queueDBJob $ JobSynchroniseLdapUser uid
|
||||||
|
lift . queueDBJob . JobQueueNotification $ NotificationUserAuthModeUpdate uid (newUser ^. _userAuthentication)
|
||||||
|
when (aufAuth == AuthKindPWHash) $
|
||||||
|
lift . queueDBJob $ JobSendPasswordReset uid
|
||||||
|
return uid
|
||||||
|
|
||||||
|
|
||||||
getAdminUserAddR, postAdminUserAddR :: Handler Html
|
getAdminUserAddR, postAdminUserAddR :: Handler Html
|
||||||
getAdminUserAddR = postAdminUserAddR
|
getAdminUserAddR = postAdminUserAddR
|
||||||
postAdminUserAddR = do
|
postAdminUserAddR = do
|
||||||
((userRes, userView), userEnctype) <- runFormPost $ adminUserForm Nothing
|
((userRes, userView), userEnctype) <- runFormPost $ adminUserForm Nothing
|
||||||
|
formResult userRes $ addNewUser >=> \case
|
||||||
formResult userRes $ \AdminUserForm{..} -> do
|
(Just uid) -> do
|
||||||
now <- liftIO getCurrentTime
|
|
||||||
UserDefaultConf{..} <- getsYesod $ view _appUserDefaults
|
|
||||||
|
|
||||||
let
|
|
||||||
newUser@User{..} = User
|
|
||||||
{ userIdent = aufIdent
|
|
||||||
, userMaxFavourites = userDefaultMaxFavourites
|
|
||||||
, userMaxFavouriteTerms = userDefaultMaxFavouriteTerms
|
|
||||||
, userTheme = userDefaultTheme
|
|
||||||
, userDateTimeFormat = userDefaultDateTimeFormat
|
|
||||||
, userDateFormat = userDefaultDateFormat
|
|
||||||
, userTimeFormat = userDefaultTimeFormat
|
|
||||||
, userDownloadFiles = userDefaultDownloadFiles
|
|
||||||
, userWarningDays = userDefaultWarningDays
|
|
||||||
, userShowSex = userDefaultShowSex
|
|
||||||
, userExamOfficeGetSynced = userDefaultExamOfficeGetSynced
|
|
||||||
, userExamOfficeGetLabels = userDefaultExamOfficeGetLabels
|
|
||||||
, userNotificationSettings = def
|
|
||||||
, userLanguages = Nothing
|
|
||||||
, userCsvOptions = def
|
|
||||||
, userTokensIssuedAfter = Nothing
|
|
||||||
, userCreated = now
|
|
||||||
, userLastLdapSynchronisation = Nothing
|
|
||||||
, userLdapPrimaryKey = Nothing
|
|
||||||
, userLastAuthentication = Nothing
|
|
||||||
, userEmail = aufEmail
|
|
||||||
, userDisplayName = aufDisplayName
|
|
||||||
, userDisplayEmail = aufDisplayEmail
|
|
||||||
, userFirstName = aufFirstName
|
|
||||||
, userSurname = aufSurname
|
|
||||||
, userTitle = aufTitle
|
|
||||||
, userSex = aufSex
|
|
||||||
, userMobile = aufMobile
|
|
||||||
, userTelephone = aufTelephone
|
|
||||||
, userCompanyPersonalNumber = aufFPersonalNumber
|
|
||||||
, userCompanyDepartment = aufFDepartment
|
|
||||||
, userPostAddress = aufPostAddress
|
|
||||||
, userPrefersPostal = aufPrefersPostal
|
|
||||||
, userPinPassword = aufPinPassword
|
|
||||||
, userMatrikelnummer = aufMatriculation
|
|
||||||
, userAuthentication = mkAuthMode aufAuth
|
|
||||||
}
|
|
||||||
|
|
||||||
didInsert <- runDBJobs . runMaybeT $ do
|
|
||||||
uid <- MaybeT $ insertUnique newUser
|
|
||||||
lift . queueDBJob $ JobSynchroniseLdapUser uid
|
|
||||||
lift . queueDBJob . JobQueueNotification $ NotificationUserAuthModeUpdate uid userAuthentication
|
|
||||||
when (aufAuth == AuthKindPWHash) $
|
|
||||||
lift . queueDBJob $ JobSendPasswordReset uid
|
|
||||||
return uid
|
|
||||||
|
|
||||||
case didInsert of
|
|
||||||
Just uid -> do
|
|
||||||
addMessageI Success MsgUserAdded
|
addMessageI Success MsgUserAdded
|
||||||
cID <- encrypt uid
|
cID <- encrypt uid
|
||||||
redirect $ AdminUserR cID
|
redirect $ AdminUserR cID
|
||||||
|
|||||||
@ -21,7 +21,11 @@ import Utils.Avs
|
|||||||
|
|
||||||
import qualified Data.Set as Set
|
import qualified Data.Set as Set
|
||||||
import qualified Data.Map as Map
|
import qualified Data.Map as Map
|
||||||
-- import qualified Data.Text as Text
|
import qualified Data.Text.Encoding as Text
|
||||||
|
|
||||||
|
import qualified Data.CaseInsensitive as CI
|
||||||
|
import Auth.LDAP (ldapUserPrincipalName)
|
||||||
|
import Foundation.Yesod.Auth (upsertCampusUser,CampusUserConversionException())
|
||||||
|
|
||||||
import Handler.Users.Add
|
import Handler.Users.Add
|
||||||
|
|
||||||
@ -34,8 +38,10 @@ data AvsException
|
|||||||
= AvsInterfaceUnavailable -- Interface to AVS was not configured at startup or does not respond
|
= AvsInterfaceUnavailable -- Interface to AVS was not configured at startup or does not respond
|
||||||
| AvsUserUnassociated UserId -- Manipulating AVS Data for a user that is not linked to AVS yet
|
| AvsUserUnassociated UserId -- Manipulating AVS Data for a user that is not linked to AVS yet
|
||||||
| AvsUserUnknownByAvs AvsPersonId -- AvsPersionId not (or no longer) found in AVS DB
|
| AvsUserUnknownByAvs AvsPersonId -- AvsPersionId not (or no longer) found in AVS DB
|
||||||
|
| AvsUserAmbiguous -- Multiple matching existing users found in our DB
|
||||||
| AvsPersonSearchEmpty -- AvsPersonSearch returned empty result
|
| AvsPersonSearchEmpty -- AvsPersonSearch returned empty result
|
||||||
| AvsPersonSearchAmbiguous -- AvsPersonSearch returned more than one result
|
| AvsPersonSearchAmbiguous -- AvsPersonSearch returned more than one result
|
||||||
|
|
||||||
deriving (Show, Generic, Typeable)
|
deriving (Show, Generic, Typeable)
|
||||||
instance Exception AvsException
|
instance Exception AvsException
|
||||||
|
|
||||||
@ -119,13 +125,29 @@ or
|
|||||||
-- Throws errors if the avsInterface in unavailable or the user is non-unique within external AVS DB (should never happen).
|
-- Throws errors if the avsInterface in unavailable or the user is non-unique within external AVS DB (should never happen).
|
||||||
upsertAvsUser :: AvsPersonId -> Handler (Maybe UserId)
|
upsertAvsUser :: AvsPersonId -> Handler (Maybe UserId)
|
||||||
upsertAvsUser api = do
|
upsertAvsUser api = do
|
||||||
mbuid <- runDB $ getBy $ UniqueUserAvsId api
|
|
||||||
mbapd <- lookupAvsUser api
|
mbapd <- lookupAvsUser api
|
||||||
|
mbuid <- runDB $ do
|
||||||
|
mbuid <- getBy (UniqueUserAvsId api)
|
||||||
|
case (mbuid, mbapd) of
|
||||||
|
(Nothing, Just AvsDataPerson{..}) -- FRADriver User does not exist yet, but found in AVS and has Internal Personal Number
|
||||||
|
| Just persNo <- avsPersonInternalPersonalNo -> do
|
||||||
|
candidates <- selectKeysList [UserCompanyPersonalNumber ==. avsPersonInternalPersonalNo] []
|
||||||
|
case candidates of
|
||||||
|
[uid] -> insertUniqueEntity $ UserAvs api uid
|
||||||
|
(_:_) -> throwM AvsUserAmbiguous
|
||||||
|
[] -> do
|
||||||
|
upsRes :: Either CampusUserConversionException (Entity User) <- try $ upsertCampusUser UpsertCampusUserGuessUser [(ldapUserPrincipalName,[Text.encodeUtf8 persNo])]
|
||||||
|
case upsRes of
|
||||||
|
Right Entity{entityKey=uid} -> insertUniqueEntity $ UserAvs api uid
|
||||||
|
_other -> return mbuid -- ==Nothing -- user could not be created somehow
|
||||||
|
_other -> return mbuid
|
||||||
case (mbuid, mbapd) of
|
case (mbuid, mbapd) of
|
||||||
( _ , Nothing) -> throwM $ AvsUserUnknownByAvs api -- this should never happen
|
( _ , Nothing ) -> throwM $ AvsUserUnknownByAvs api -- User not found in AVS at all, i.e. no valid card exists yet
|
||||||
(Nothing, Just AvsDataPerson{..}) -> do -- unknown user, must be created
|
(Nothing, Just AvsDataPerson{..}) -> do -- No LDAP User, but found in AVS; create user
|
||||||
-- if | Just ipn <- avsPersonInternalPersonalNo -> TODO?
|
let firmAddress = mergeFirmAddress <$> guessLicenceAddress avsPersonPersonCards
|
||||||
let _newUsr = AdminUserForm
|
bestCard = Set.lookupMax avsPersonPersonCards
|
||||||
|
fakeIdent = CI.mk $ tshow api
|
||||||
|
newUsr = AdminUserForm
|
||||||
{ aufTitle = Nothing
|
{ aufTitle = Nothing
|
||||||
, aufFirstName = avsPersonFirstName
|
, aufFirstName = avsPersonFirstName
|
||||||
, aufSurname = avsPersonLastName
|
, aufSurname = avsPersonLastName
|
||||||
@ -137,17 +159,18 @@ upsertAvsUser api = do
|
|||||||
, aufTelephone = Nothing
|
, aufTelephone = Nothing
|
||||||
, aufFPersonalNumber = avsPersonInternalPersonalNo
|
, aufFPersonalNumber = avsPersonInternalPersonalNo
|
||||||
, aufFDepartment = Nothing
|
, aufFDepartment = Nothing
|
||||||
, aufPostAddress = error "TODO" -- CONTINUE HERE
|
, aufPostAddress = plaintextToStoredMarkup <$> firmAddress
|
||||||
, aufPrefersPostal = error "TODO" -- CONTINUE HERE
|
, aufPrefersPostal = isJust firmAddress
|
||||||
, aufPinPassword = error "TODO" -- CONTINUE HERE
|
, aufPinPassword = getFullCardNo <$> bestCard
|
||||||
, aufEmail = ""
|
, aufEmail = fakeIdent -- Email is unknown in this version of the avs query, to be updated later (FUTURE TODO)
|
||||||
, aufIdent = error "TODO" -- CONTINUE HERE
|
, aufIdent = fakeIdent -- use AvsPersonId instead
|
||||||
, aufAuth = error "TODO" -- CONTINUE HERE AuthKindNoLogin or AuthKindLDAP if ldap search worked
|
, aufAuth = maybe AuthKindNoLogin (const AuthKindLDAP) avsPersonInternalPersonalNo -- FUTURE TODO: if email is known, use AuthKinfPWHash for email invite, if no internal personal number is known
|
||||||
}
|
}
|
||||||
|
_ <- addNewUser newUsr
|
||||||
-- _newAvs = UserAvs avsPersonPersonID uid
|
-- _newAvs = UserAvs avsPersonPersonID uid
|
||||||
-- _newAvsCards = UserAvsCard
|
-- _newAvsCards = UserAvsCard
|
||||||
error "TODO" -- CONTINUE HERE
|
error "TODO" -- CONTINUE HERE
|
||||||
(Just _uid, Just _apd) -> do -- known user
|
(Just (Entity _ UserAvs{}), Just AvsDataPerson{}) -> -- known user, do some updates
|
||||||
error "TODO" -- CONTINUE HERE
|
error "TODO" -- CONTINUE HERE
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -80,7 +80,7 @@ instance FromJSON SloppyBool where
|
|||||||
-- AVS Datatypes --
|
-- AVS Datatypes --
|
||||||
-------------------
|
-------------------
|
||||||
|
|
||||||
type AvsInternalPersonalNo = Text -- type synonym for claritty/documentation within types
|
type AvsInternalPersonalNo = Text -- type synonym for clarity/documentation within types
|
||||||
|
|
||||||
-- CompleteCardNo = xxxxxxxx.y
|
-- CompleteCardNo = xxxxxxxx.y
|
||||||
-- where x is an 8 digit AvsCardNo prefixed by zeros
|
-- where x is an 8 digit AvsCardNo prefixed by zeros
|
||||||
@ -246,6 +246,8 @@ instance ToJSON AvsDataPersonCard where
|
|||||||
]
|
]
|
||||||
derivePersistFieldJSON ''AvsDataPersonCard
|
derivePersistFieldJSON ''AvsDataPersonCard
|
||||||
|
|
||||||
|
getFullCardNo :: AvsDataPersonCard -> Text
|
||||||
|
getFullCardNo AvsDataPersonCard{avsDataCardNo, avsDataVersionNo} = avsCardNo avsDataCardNo <> Text.cons '.' avsDataVersionNo
|
||||||
|
|
||||||
data AvsStatusPerson = AvsStatusPerson
|
data AvsStatusPerson = AvsStatusPerson
|
||||||
{ avsStatusPersonID :: AvsPersonId
|
{ avsStatusPersonID :: AvsPersonId
|
||||||
|
|||||||
@ -87,16 +87,21 @@ getValidLicence cutoff licence' cards = Set.lookupMax validLicenceCards
|
|||||||
cardMatch AvsDataPersonCard{..} =
|
cardMatch AvsDataPersonCard{..} =
|
||||||
avsDataValid && (avsDataValidTo >= cutoff) && (licence `Set.member` avsDataCardAreas)
|
avsDataValid && (avsDataValidTo >= cutoff) && (licence `Set.member` avsDataCardAreas)
|
||||||
|
|
||||||
guessLicenceAddress :: Set AvsDataPersonCard -> Maybe (Maybe Text, Text)
|
guessLicenceAddress :: Set AvsDataPersonCard -> Maybe (Maybe Text, Text, AvsDataPersonCard)
|
||||||
guessLicenceAddress cards
|
guessLicenceAddress cards
|
||||||
| Just c <- Set.lookupMax cards
|
| Just c <- Set.lookupMax cards
|
||||||
, AvsDataPersonCard{..} <- Set.foldr pickLicenceAddress c cards
|
, card@AvsDataPersonCard{..} <- Set.foldr pickLicenceAddress c cards
|
||||||
, Just street <- avsDataStreet
|
, Just street <- avsDataStreet
|
||||||
, Just pcode <- avsDataPostalCode
|
, Just pcode <- avsDataPostalCode
|
||||||
, Just city <- avsDataCity
|
, Just city <- avsDataCity
|
||||||
= Just (avsDataFirm, Text.unlines [street, Text.unwords [pcode, city]])
|
= Just (avsDataFirm, Text.unlines [street, Text.unwords [pcode, city]], card)
|
||||||
| otherwise = Nothing
|
| otherwise = Nothing
|
||||||
|
|
||||||
|
-- | Helper for guessLicenceAddress
|
||||||
|
mergeFirmAddress :: (Maybe Text, Text, a) -> Text
|
||||||
|
mergeFirmAddress (Nothing , addr, _) = addr
|
||||||
|
mergeFirmAddress (Just firm, addr, _) = firm <> Text.cons '\n' addr
|
||||||
|
|
||||||
hasAddress :: AvsDataPersonCard -> Bool
|
hasAddress :: AvsDataPersonCard -> Bool
|
||||||
hasAddress AvsDataPersonCard{..} = isJust avsDataStreet && isJust avsDataCity && isJust avsDataPostalCode
|
hasAddress AvsDataPersonCard{..} = isJust avsDataStreet && isJust avsDataCity && isJust avsDataPostalCode
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user