fix(avs): company superior emails become company wide supervisors
This commit is contained in:
parent
975bf13d9c
commit
37efc89e07
@ -67,6 +67,7 @@ BearerTokenExpiresTip: Wird der Ablaufzeitpunkt überschrieben und kein Ablaufze
|
|||||||
BearerTokenOverrideStart: Startzeitpunkt
|
BearerTokenOverrideStart: Startzeitpunkt
|
||||||
BearerTokenOverrideStartTip: Wird kein Startzeitpunkt angegeben, wird bei Verwendung des Tokens nur der Ablaufzeitpunkt überprüft.
|
BearerTokenOverrideStartTip: Wird kein Startzeitpunkt angegeben, wird bei Verwendung des Tokens nur der Ablaufzeitpunkt überprüft.
|
||||||
HeadingAdminTokens: Tokens ausstellen
|
HeadingAdminTokens: Tokens ausstellen
|
||||||
|
UserUnknown: Unbekannter Benutzer:in
|
||||||
|
|
||||||
#templates adminFeautures
|
#templates adminFeautures
|
||||||
StudyFeaturesDegrees: Abschlüsse
|
StudyFeaturesDegrees: Abschlüsse
|
||||||
@ -127,9 +128,11 @@ AdminProblemCreated: Erkannt
|
|||||||
AdminProblemInfo: Problembeschreibung
|
AdminProblemInfo: Problembeschreibung
|
||||||
AdminProblemsSolved n@Int: #{pluralDEeN n "Admin Problem"} als erledigt markiert
|
AdminProblemsSolved n@Int: #{pluralDEeN n "Admin Problem"} als erledigt markiert
|
||||||
AdminProblemsReopened n@Int: #{pluralDEeN n "Admin Problem"} erneut eröffnet
|
AdminProblemsReopened n@Int: #{pluralDEeN n "Admin Problem"} erneut eröffnet
|
||||||
AdminProblemNewCompany: Neue Firma aus AVS automatisch erstellt; prüfen und ggf. Standardansprechpartner eintragen
|
AdminProblemNewCompany: Neue Firma über AVS automatisch erstellt; prüfen und ggf. Standardansprechpartner eintragen
|
||||||
AdminProblemSupervisorNewCompany b@Bool: Dieser Standardansprechpartner #{boolText mempty "mit Standardumleitung" b} wechselte zu neuer Firma
|
AdminProblemSupervisorNewCompany b@Bool: Standardansprechpartner #{boolText mempty "mit Standardumleitung" b} wechselte zu neuer Firma
|
||||||
AdminProblemSupervisorLeftCompany b@Bool: Einziger Standardansprechpartner #{boolText mempty "mit Standardumleitung" b} dieses Fahrers wechselte zu neuer Firma
|
AdminProblemSupervisorLeftCompany b@Bool: Einziger Standardansprechpartner #{boolText mempty "mit Standardumleitung" b} dieses Fahrers wechselte zu neuer Firma
|
||||||
|
AdminProblemCompanySuperiorChange: Neuer firmenweiter Vorgesetzer.
|
||||||
|
AdminProblemCompanySuperiorPrevious: Ehemaliger Vorgesetzer:
|
||||||
AdminProblemNewlyUnsupervised: Fahrer hat keinen Firmenansprechpartner mehr nach AVS Firmenwechsel zu Firma
|
AdminProblemNewlyUnsupervised: Fahrer hat keinen Firmenansprechpartner mehr nach AVS Firmenwechsel zu Firma
|
||||||
AdminProblemUser: Betroffener
|
AdminProblemUser: Betroffener
|
||||||
ProblemTableMarkSolved: Als erledigt markieren
|
ProblemTableMarkSolved: Als erledigt markieren
|
||||||
|
|||||||
@ -67,6 +67,7 @@ BearerTokenExpiresTip: If no expiration time is given, the token will not expire
|
|||||||
BearerTokenOverrideStart: Start time
|
BearerTokenOverrideStart: Start time
|
||||||
BearerTokenOverrideStartTip: If no start time is given, only the expiration time will be checked when the token is used.
|
BearerTokenOverrideStartTip: If no start time is given, only the expiration time will be checked when the token is used.
|
||||||
HeadingAdminTokens: Issue tokens
|
HeadingAdminTokens: Issue tokens
|
||||||
|
UserUnknown: User unknown
|
||||||
|
|
||||||
#templates adminfeatures
|
#templates adminfeatures
|
||||||
StudyFeaturesDegrees: Degrees
|
StudyFeaturesDegrees: Degrees
|
||||||
@ -128,8 +129,10 @@ AdminProblemInfo: Problem
|
|||||||
AdminProblemsSolved n: #{pluralENsN n "admin problem"} marked as solved
|
AdminProblemsSolved n: #{pluralENsN n "admin problem"} marked as solved
|
||||||
AdminProblemsReopened n: #{pluralENsN n "admin problem"} reopened
|
AdminProblemsReopened n: #{pluralENsN n "admin problem"} reopened
|
||||||
AdminProblemNewCompany: New company from AVS; verify and add default supervisors
|
AdminProblemNewCompany: New company from AVS; verify and add default supervisors
|
||||||
AdminProblemSupervisorNewCompany b: This default company supervisor #{boolText mempty "with reroute" b} changed to new company
|
AdminProblemSupervisorNewCompany b: Default company supervisor #{boolText mempty "with reroute" b} changed to new company
|
||||||
AdminProblemSupervisorLeftCompany b: Only default company supervisor #{boolText mempty "with reroute" b} for this user changed to new company
|
AdminProblemSupervisorLeftCompany b: Only default company supervisor #{boolText mempty "with reroute" b} for this user changed to new company
|
||||||
|
AdminProblemCompanySuperiorChange: New company wide superior.
|
||||||
|
AdminProblemCompanySuperiorPrevious: Previous superior:
|
||||||
AdminProblemNewlyUnsupervised: Driver has no longer a company default supervisor after AVS update at new company
|
AdminProblemNewlyUnsupervised: Driver has no longer a company default supervisor after AVS update at new company
|
||||||
AdminProblemUser: Affected
|
AdminProblemUser: Affected
|
||||||
ProblemTableMarkSolved: Mark done
|
ProblemTableMarkSolved: Mark done
|
||||||
|
|||||||
@ -185,7 +185,7 @@ data Transaction
|
|||||||
}
|
}
|
||||||
| TransactionLmsStart
|
| TransactionLmsStart
|
||||||
{ transactionQualification :: QualificationId
|
{ transactionQualification :: QualificationId
|
||||||
, transactionLmsIdent :: LmsIdent
|
, transactionLmsIdent :: LmsIdent
|
||||||
, transactionLmsUser :: UserId
|
, transactionLmsUser :: UserId
|
||||||
, transactionLmsUserKey :: LmsUserId
|
, transactionLmsUserKey :: LmsUserId
|
||||||
}
|
}
|
||||||
@ -216,7 +216,7 @@ data Transaction
|
|||||||
| TransactionQualificationUserEdit -- Note that a renewal always entails unblocking as well!
|
| TransactionQualificationUserEdit -- Note that a renewal always entails unblocking as well!
|
||||||
{ transactionUser :: UserId -- qualification holder that is updated
|
{ transactionUser :: UserId -- qualification holder that is updated
|
||||||
, transactionQualificationUser :: QualificationUserId -- not really necessary, maybe remove?
|
, transactionQualificationUser :: QualificationUserId -- not really necessary, maybe remove?
|
||||||
, transactionQualification :: QualificationId
|
, transactionQualification :: QualificationId
|
||||||
, transactionQualificationValidUntil :: Day
|
, transactionQualificationValidUntil :: Day
|
||||||
, transactionQualificationScheduleRenewal :: Maybe Bool -- Maybe, because some update may leave it unchanged (also avoids DB Migration)
|
, transactionQualificationScheduleRenewal :: Maybe Bool -- Maybe, because some update may leave it unchanged (also avoids DB Migration)
|
||||||
, transactionNote :: Maybe Text
|
, transactionNote :: Maybe Text
|
||||||
@ -265,7 +265,7 @@ data AdminProblem
|
|||||||
= AdminProblemNewCompany -- new company was noticed, presumably without supervisors
|
= AdminProblemNewCompany -- new company was noticed, presumably without supervisors
|
||||||
{ adminProblemCompany :: CompanyId
|
{ adminProblemCompany :: CompanyId
|
||||||
}
|
}
|
||||||
| AdminProblemSupervisorNewCompany
|
| AdminProblemSupervisorNewCompany
|
||||||
{ adminProblemUser :: UserId -- a default supervisor has changed company
|
{ adminProblemUser :: UserId -- a default supervisor has changed company
|
||||||
, adminProblemCompany :: CompanyId -- old company where the user had default supervisor rights
|
, adminProblemCompany :: CompanyId -- old company where the user had default supervisor rights
|
||||||
, adminProblemCompanyNew :: CompanyId -- new company of the user
|
, adminProblemCompanyNew :: CompanyId -- new company of the user
|
||||||
@ -276,13 +276,18 @@ data AdminProblem
|
|||||||
, adminProblemCompany :: CompanyId -- old company
|
, adminProblemCompany :: CompanyId -- old company
|
||||||
, adminProblemSupervisorReroute :: Bool -- reroute included?
|
, adminProblemSupervisorReroute :: Bool -- reroute included?
|
||||||
}
|
}
|
||||||
| AdminProblemNewlyUnsupervised
|
| AdminProblemCompanySuperiorChange -- a company received a new superior user through AVS
|
||||||
|
{ adminProblemUser :: UserId -- new superior user
|
||||||
|
, adminProblemCompany :: CompanyId -- affected company
|
||||||
|
, adminProblemUserOld :: Maybe UserId -- previous superior
|
||||||
|
}
|
||||||
|
| AdminProblemNewlyUnsupervised
|
||||||
{ adminProblemUser :: UserId -- user who had a supervisor but no longer has, due to user company change
|
{ adminProblemUser :: UserId -- user who had a supervisor but no longer has, due to user company change
|
||||||
, adminProblemCompanyOld :: Maybe CompanyId -- old company
|
, adminProblemCompanyOld :: Maybe CompanyId -- old company
|
||||||
, adminProblemCompanyNew :: CompanyId -- new company of the user
|
, adminProblemCompanyNew :: CompanyId -- new company of the user
|
||||||
}
|
}
|
||||||
| AdminProblemUnknown -- miscellanous problem, just displaying text
|
| AdminProblemUnknown -- miscellanous problem, just displaying text
|
||||||
{ adminProblemText :: Text
|
{ adminProblemText :: Text
|
||||||
}
|
}
|
||||||
deriving (Eq, Ord, Read, Show, Generic)
|
deriving (Eq, Ord, Read, Show, Generic)
|
||||||
|
|
||||||
|
|||||||
@ -55,7 +55,7 @@ data ProblemTableActionData = ProblemTableMarkSolvedData
|
|||||||
deriving (Eq, Ord, Read, Show, Generic)
|
deriving (Eq, Ord, Read, Show, Generic)
|
||||||
|
|
||||||
|
|
||||||
-- Handlers
|
-- Handlers
|
||||||
getAdminR :: Handler Html
|
getAdminR :: Handler Html
|
||||||
getAdminR = redirect AdminProblemsR
|
getAdminR = redirect AdminProblemsR
|
||||||
|
|
||||||
@ -63,7 +63,7 @@ getAdminProblemsR, postAdminProblemsR :: Handler Html
|
|||||||
getAdminProblemsR = handleAdminProblems Nothing
|
getAdminProblemsR = handleAdminProblems Nothing
|
||||||
|
|
||||||
handleAdminProblems :: Maybe Widget -> Handler Html
|
handleAdminProblems :: Maybe Widget -> Handler Html
|
||||||
handleAdminProblems mbProblemTable = do
|
handleAdminProblems mbProblemTable = do
|
||||||
now <- liftIO getCurrentTime
|
now <- liftIO getCurrentTime
|
||||||
let nowaday = utctDay now
|
let nowaday = utctDay now
|
||||||
cutOffOldDays = 1
|
cutOffOldDays = 1
|
||||||
@ -75,21 +75,21 @@ handleAdminProblems mbProblemTable = do
|
|||||||
msgErrorTooltip <- messageI Error MsgMessageError
|
msgErrorTooltip <- messageI Error MsgMessageError
|
||||||
|
|
||||||
let flagError = messageTooltip . bool msgErrorTooltip msgSuccessTooltip
|
let flagError = messageTooltip . bool msgErrorTooltip msgSuccessTooltip
|
||||||
flagWarning = messageTooltip . bool msgWarningTooltip msgSuccessTooltip
|
flagWarning = messageTooltip . bool msgWarningTooltip msgSuccessTooltip
|
||||||
flagNonZero :: Int -> Widget
|
flagNonZero :: Int -> Widget
|
||||||
flagNonZero n | n <= 0 = flagError True
|
flagNonZero n | n <= 0 = flagError True
|
||||||
| otherwise = messageTooltip =<< handlerToWidget (messageI Error (MsgProblemsDriverSynch n))
|
| otherwise = messageTooltip =<< handlerToWidget (messageI Error (MsgProblemsDriverSynch n))
|
||||||
|
|
||||||
(usersAreReachable, driversHaveAvsIds, rDriversHaveFs, noStalePrintJobs, noBadAPCids, (interfaceOks, interfaceTable)) <- runDB $ (,,,,,)
|
(usersAreReachable, driversHaveAvsIds, rDriversHaveFs, noStalePrintJobs, noBadAPCids, (interfaceOks, interfaceTable)) <- runDB $ (,,,,,)
|
||||||
<$> areAllUsersReachable
|
<$> areAllUsersReachable
|
||||||
<*> allDriversHaveAvsId now
|
<*> allDriversHaveAvsId now
|
||||||
<*> allRDriversHaveFs now
|
<*> allRDriversHaveFs now
|
||||||
<*> (not <$> exists [PrintJobAcknowledged ==. Nothing, PrintJobCreated <. cutOffOldTime])
|
<*> (not <$> exists [PrintJobAcknowledged ==. Nothing, PrintJobCreated <. cutOffOldTime])
|
||||||
<*> (not <$> exists [PrintAcknowledgeProcessed ==. False])
|
<*> (not <$> exists [PrintAcknowledgeProcessed ==. False])
|
||||||
<*> mkInterfaceLogTable flagError mempty
|
<*> mkInterfaceLogTable flagError mempty
|
||||||
let interfacesBadNr = length $ filter (not . snd) interfaceOks
|
let interfacesBadNr = length $ filter (not . snd) interfaceOks
|
||||||
-- interfacesOk = all snd interfaceOks
|
-- interfacesOk = all snd interfaceOks
|
||||||
|
|
||||||
diffLics <- try retrieveDifferingLicences >>= \case
|
diffLics <- try retrieveDifferingLicences >>= \case
|
||||||
-- (Left (UnsupportedContentType "text/html" resp)) -> Left $ text2widget "Html received"
|
-- (Left (UnsupportedContentType "text/html" resp)) -> Left $ text2widget "Html received"
|
||||||
(Left e) -> return $ Left $ text2widget $ tshow (e :: SomeException)
|
(Left e) -> return $ Left $ text2widget $ tshow (e :: SomeException)
|
||||||
@ -118,13 +118,13 @@ handleAdminProblems mbProblemTable = do
|
|||||||
setTitleI MsgProblemsHeading
|
setTitleI MsgProblemsHeading
|
||||||
$(widgetFile "admin-problems")
|
$(widgetFile "admin-problems")
|
||||||
|
|
||||||
postAdminProblemsR = do
|
postAdminProblemsR = do
|
||||||
(problemLogRes, problemLogTable) <- runDB mkProblemLogTable
|
(problemLogRes, problemLogTable) <- runDB mkProblemLogTable
|
||||||
formResult problemLogRes procProblems
|
formResult problemLogRes procProblems
|
||||||
handleAdminProblems $ Just problemLogTable
|
handleAdminProblems $ Just problemLogTable
|
||||||
where
|
where
|
||||||
procProblems :: (ProblemTableActionData, Set ProblemLogId) -> Handler ()
|
procProblems :: (ProblemTableActionData, Set ProblemLogId) -> Handler ()
|
||||||
procProblems (ProblemTableMarkSolvedData , pids) = actUpdate True pids
|
procProblems (ProblemTableMarkSolvedData , pids) = actUpdate True pids
|
||||||
procProblems (ProblemTableMarkUnsolvedData, pids) = actUpdate False pids
|
procProblems (ProblemTableMarkUnsolvedData, pids) = actUpdate False pids
|
||||||
|
|
||||||
actUpdate markdone pids = do
|
actUpdate markdone pids = do
|
||||||
@ -146,7 +146,7 @@ getProblemUnreachableR = do
|
|||||||
setTitleI MsgProblemsUnreachableHeading
|
setTitleI MsgProblemsUnreachableHeading
|
||||||
[whamlet|
|
[whamlet|
|
||||||
<section>
|
<section>
|
||||||
#{length unreachables} _{MsgProblemsUnreachableBody}
|
#{length unreachables} _{MsgProblemsUnreachableBody}
|
||||||
<ul>
|
<ul>
|
||||||
$forall usr <- unreachables
|
$forall usr <- unreachables
|
||||||
<li>
|
<li>
|
||||||
@ -154,8 +154,8 @@ getProblemUnreachableR = do
|
|||||||
|]
|
|]
|
||||||
|
|
||||||
getProblemFbutNoR :: Handler Html
|
getProblemFbutNoR :: Handler Html
|
||||||
getProblemFbutNoR = do
|
getProblemFbutNoR = do
|
||||||
now <- liftIO getCurrentTime
|
now <- liftIO getCurrentTime
|
||||||
rnofs <- runDB $ E.select $ retrieveDriversRWithoutF now
|
rnofs <- runDB $ E.select $ retrieveDriversRWithoutF now
|
||||||
siteLayoutMsg MsgProblemsRWithoutFHeading $ do
|
siteLayoutMsg MsgProblemsRWithoutFHeading $ do
|
||||||
setTitleI MsgProblemsRWithoutFHeading
|
setTitleI MsgProblemsRWithoutFHeading
|
||||||
@ -169,8 +169,8 @@ getProblemFbutNoR = do
|
|||||||
|]
|
|]
|
||||||
|
|
||||||
getProblemWithoutAvsId :: Handler Html
|
getProblemWithoutAvsId :: Handler Html
|
||||||
getProblemWithoutAvsId = do
|
getProblemWithoutAvsId = do
|
||||||
now <- liftIO getCurrentTime
|
now <- liftIO getCurrentTime
|
||||||
rnofs <- runDB $ E.select $ retrieveDriversWithoutAvsId now
|
rnofs <- runDB $ E.select $ retrieveDriversWithoutAvsId now
|
||||||
siteLayoutMsg MsgProblemsNoAvsIdHeading $ do
|
siteLayoutMsg MsgProblemsNoAvsIdHeading $ do
|
||||||
setTitleI MsgProblemsNoAvsIdHeading
|
setTitleI MsgProblemsNoAvsIdHeading
|
||||||
@ -185,40 +185,40 @@ getProblemWithoutAvsId = do
|
|||||||
|
|
||||||
{-
|
{-
|
||||||
mkUnreachableUsersTable = do
|
mkUnreachableUsersTable = do
|
||||||
let dbtSQLQuery user -> do
|
let dbtSQLQuery user -> do
|
||||||
E.where_ $ E.isNothing (user E.^. UserPostAddress)
|
E.where_ $ E.isNothing (user E.^. UserPostAddress)
|
||||||
E.&&. E.not_ ((user E.^. UserEmail) `E.like` E.val "%@%.%")
|
E.&&. E.not_ ((user E.^. UserEmail) `E.like` E.val "%@%.%")
|
||||||
pure user
|
pure user
|
||||||
dbtRowKey = (E.^. UserId)
|
dbtRowKey = (E.^. UserId)
|
||||||
dbtProj = dbtProjId
|
dbtProj = dbtProjId
|
||||||
dbtColonnade =
|
dbtColonnade =
|
||||||
-}
|
-}
|
||||||
|
|
||||||
areAllUsersReachable :: DB Bool
|
areAllUsersReachable :: DB Bool
|
||||||
-- areAllUsersReachable = isNothing <$> E.selectOne retrieveUnreachableUsers'
|
-- areAllUsersReachable = isNothing <$> E.selectOne retrieveUnreachableUsers'
|
||||||
-- areAllUsersReachable = E.selectNotExists retrieveUnreachableUsers'
|
-- areAllUsersReachable = E.selectNotExists retrieveUnreachableUsers'
|
||||||
areAllUsersReachable = null <$> retrieveUnreachableUsers
|
areAllUsersReachable = null <$> retrieveUnreachableUsers
|
||||||
|
|
||||||
-- retrieveUnreachableUsers' :: E.SqlQuery (E.SqlExpr (Entity User))
|
-- retrieveUnreachableUsers' :: E.SqlQuery (E.SqlExpr (Entity User))
|
||||||
-- retrieveUnreachableUsers' = do
|
-- retrieveUnreachableUsers' = do
|
||||||
-- user <- E.from $ E.table @User
|
-- user <- E.from $ E.table @User
|
||||||
-- E.where_ $ E.isNothing (user E.^. UserPostAddress)
|
-- E.where_ $ E.isNothing (user E.^. UserPostAddress)
|
||||||
-- E.&&. (E.isNothing (user E.^. UserCompanyDepartment) E.||. user E.^. UserCompanyPersonalNumber `E.ilike` E.justVal "E%")
|
-- E.&&. (E.isNothing (user E.^. UserCompanyDepartment) E.||. user E.^. UserCompanyPersonalNumber `E.ilike` E.justVal "E%")
|
||||||
-- E.&&. E.not_ ((user E.^. UserDisplayEmail) `E.like` E.val "%@%.%")
|
-- E.&&. E.not_ ((user E.^. UserDisplayEmail) `E.like` E.val "%@%.%")
|
||||||
-- E.&&. E.not_ ((user E.^. UserEmail) `E.like` E.val "%@%.%")
|
-- E.&&. E.not_ ((user E.^. UserEmail) `E.like` E.val "%@%.%")
|
||||||
-- return user
|
-- return user
|
||||||
|
|
||||||
retrieveUnreachableUsers :: DB [Entity User]
|
retrieveUnreachableUsers :: DB [Entity User]
|
||||||
retrieveUnreachableUsers = do
|
retrieveUnreachableUsers = do
|
||||||
emailOnlyUsers <- E.select $ do
|
emailOnlyUsers <- E.select $ do
|
||||||
user <- E.from $ E.table @User
|
user <- E.from $ E.table @User
|
||||||
E.where_ $ E.isNothing (user E.^. UserPostAddress)
|
E.where_ $ E.isNothing (user E.^. UserPostAddress)
|
||||||
E.&&. (E.isNothing (user E.^. UserCompanyDepartment) E.||. user E.^. UserCompanyPersonalNumber `E.ilike` E.justVal "E%")
|
E.&&. (E.isNothing (user E.^. UserCompanyDepartment) E.||. user E.^. UserCompanyPersonalNumber `E.ilike` E.justVal "E%")
|
||||||
return user
|
return user
|
||||||
filterM hasInvalidEmail emailOnlyUsers
|
filterM hasInvalidEmail emailOnlyUsers
|
||||||
where
|
where
|
||||||
hasInvalidEmail = fmap isNothing . getUserEmail
|
hasInvalidEmail = fmap isNothing . getUserEmail
|
||||||
|
|
||||||
|
|
||||||
allDriversHaveAvsId :: UTCTime -> DB Bool
|
allDriversHaveAvsId :: UTCTime -> DB Bool
|
||||||
-- allDriversHaveAvsId = fmap isNothing . E.selectOne . retrieveDriversWithoutAvsId
|
-- allDriversHaveAvsId = fmap isNothing . E.selectOne . retrieveDriversWithoutAvsId
|
||||||
@ -227,17 +227,17 @@ allDriversHaveAvsId = E.selectNotExists . retrieveDriversWithoutAvsId
|
|||||||
{-
|
{-
|
||||||
-- | Returns users more than once if they own multiple avs-related valid licences, but no AvsID is known
|
-- | Returns users more than once if they own multiple avs-related valid licences, but no AvsID is known
|
||||||
retrieveDriversWithoutAvsId' :: Day -> E.SqlQuery (E.SqlExpr (Entity User))
|
retrieveDriversWithoutAvsId' :: Day -> E.SqlQuery (E.SqlExpr (Entity User))
|
||||||
retrieveDriversWithoutAvsId' nowaday = do
|
retrieveDriversWithoutAvsId' nowaday = do
|
||||||
(usr :& qualUsr :& qual) <- E.from $ E.table @User
|
(usr :& qualUsr :& qual) <- E.from $ E.table @User
|
||||||
`E.innerJoin` E.table @QualificationUser
|
`E.innerJoin` E.table @QualificationUser
|
||||||
`E.on` (\(usr :& qualUsr) -> usr E.^. UserId E.==. qualUsr E.^. QualificationUserUser)
|
`E.on` (\(usr :& qualUsr) -> usr E.^. UserId E.==. qualUsr E.^. QualificationUserUser)
|
||||||
`E.innerJoin` E.table @Qualification
|
`E.innerJoin` E.table @Qualification
|
||||||
`E.on` (\(_usr :& qualUsr :& qual) -> qual E.^. QualificationId E.==. qualUsr E.^. QualificationUserQualification)
|
`E.on` (\(_usr :& qualUsr :& qual) -> qual E.^. QualificationId E.==. qualUsr E.^. QualificationUserQualification)
|
||||||
E.where_ $ -- is avs licence
|
E.where_ $ -- is avs licence
|
||||||
E.isJust (qual E.^. QualificationAvsLicence)
|
E.isJust (qual E.^. QualificationAvsLicence)
|
||||||
E.&&. (qualUsr & validQualification nowaday)
|
E.&&. (qualUsr & validQualification nowaday)
|
||||||
E.&&. -- AvsId is unknown
|
E.&&. -- AvsId is unknown
|
||||||
E.notExists (do
|
E.notExists (do
|
||||||
avsUsr <- E.from $ E.table @UserAvs
|
avsUsr <- E.from $ E.table @UserAvs
|
||||||
E.where_ $ avsUsr E.^. UserAvsUser E.==. usr E.^. UserId
|
E.where_ $ avsUsr E.^. UserAvsUser E.==. usr E.^. UserId
|
||||||
)
|
)
|
||||||
@ -246,20 +246,20 @@ retrieveDriversWithoutAvsId' nowaday = do
|
|||||||
|
|
||||||
-- | Returns users at most once, even if they own multiple avs-related licences, but no AvsID is known
|
-- | Returns users at most once, even if they own multiple avs-related licences, but no AvsID is known
|
||||||
retrieveDriversWithoutAvsId :: UTCTime -> E.SqlQuery (E.SqlExpr (Entity User))
|
retrieveDriversWithoutAvsId :: UTCTime -> E.SqlQuery (E.SqlExpr (Entity User))
|
||||||
retrieveDriversWithoutAvsId now = do
|
retrieveDriversWithoutAvsId now = do
|
||||||
usr <- E.from $ E.table @User
|
usr <- E.from $ E.table @User
|
||||||
E.where_ $
|
E.where_ $
|
||||||
E.exists (do -- a valid avs licence
|
E.exists (do -- a valid avs licence
|
||||||
(qual :& qualUsr) <- E.from (E.table @Qualification
|
(qual :& qualUsr) <- E.from (E.table @Qualification
|
||||||
`E.innerJoin` E.table @QualificationUser
|
`E.innerJoin` E.table @QualificationUser
|
||||||
`E.on` (\(qual :& qualUsr) -> qual E.^. QualificationId E.==. qualUsr E.^. QualificationUserQualification))
|
`E.on` (\(qual :& qualUsr) -> qual E.^. QualificationId E.==. qualUsr E.^. QualificationUserQualification))
|
||||||
E.where_ $ -- is avs licence
|
E.where_ $ -- is avs licence
|
||||||
E.isJust (qual E.^. QualificationAvsLicence)
|
E.isJust (qual E.^. QualificationAvsLicence)
|
||||||
E.&&. (qualUsr & validQualification now) -- currently valid
|
E.&&. (qualUsr & validQualification now) -- currently valid
|
||||||
E.&&. -- matches user
|
E.&&. -- matches user
|
||||||
(qualUsr E.^. QualificationUserUser E.==. usr E.^. UserId)
|
(qualUsr E.^. QualificationUserUser E.==. usr E.^. UserId)
|
||||||
)
|
)
|
||||||
E.&&.
|
E.&&.
|
||||||
E.notExists (do -- a known AvsId
|
E.notExists (do -- a known AvsId
|
||||||
avsUsr <- E.from $ E.table @UserAvs
|
avsUsr <- E.from $ E.table @UserAvs
|
||||||
E.where_ $ avsUsr E.^. UserAvsUser E.==. usr E.^. UserId
|
E.where_ $ avsUsr E.^. UserAvsUser E.==. usr E.^. UserId
|
||||||
@ -268,20 +268,20 @@ retrieveDriversWithoutAvsId now = do
|
|||||||
|
|
||||||
|
|
||||||
allRDriversHaveFs :: UTCTime -> DB Bool
|
allRDriversHaveFs :: UTCTime -> DB Bool
|
||||||
-- allRDriversHaveFs = fmap isNothing . E.selectOne . retrieveDriversRWithoutF
|
-- allRDriversHaveFs = fmap isNothing . E.selectOne . retrieveDriversRWithoutF
|
||||||
allRDriversHaveFs = E.selectNotExists . retrieveDriversRWithoutF
|
allRDriversHaveFs = E.selectNotExists . retrieveDriversRWithoutF
|
||||||
|
|
||||||
-- | Returns users at most once, even if they own multiple avs-related licences, but no AvsID is known
|
-- | Returns users at most once, even if they own multiple avs-related licences, but no AvsID is known
|
||||||
retrieveDriversRWithoutF :: UTCTime -> E.SqlQuery (E.SqlExpr (Entity User))
|
retrieveDriversRWithoutF :: UTCTime -> E.SqlQuery (E.SqlExpr (Entity User))
|
||||||
retrieveDriversRWithoutF now = do
|
retrieveDriversRWithoutF now = do
|
||||||
usr <- E.from $ E.table @User
|
usr <- E.from $ E.table @User
|
||||||
let hasValidQual lic = do
|
let hasValidQual lic = do
|
||||||
(qual :& qualUsr) <- E.from (E.table @Qualification
|
(qual :& qualUsr) <- E.from (E.table @Qualification
|
||||||
`E.innerJoin` E.table @QualificationUser
|
`E.innerJoin` E.table @QualificationUser
|
||||||
`E.on` (\(qual :& qualUsr) -> qual E.^. QualificationId E.==. qualUsr E.^. QualificationUserQualification))
|
`E.on` (\(qual :& qualUsr) -> qual E.^. QualificationId E.==. qualUsr E.^. QualificationUserQualification))
|
||||||
E.where_ $ (qual E.^. QualificationAvsLicence E.==. E.justVal lic) -- matches licence
|
E.where_ $ (qual E.^. QualificationAvsLicence E.==. E.justVal lic) -- matches licence
|
||||||
E.&&. (qualUsr E.^. QualificationUserUser E.==. usr E.^. UserId) -- matches user
|
E.&&. (qualUsr E.^. QualificationUserUser E.==. usr E.^. UserId) -- matches user
|
||||||
E.&&. (qualUsr & validQualification now) -- currently valid
|
E.&&. (qualUsr & validQualification now) -- currently valid
|
||||||
E.where_ $ E.exists (hasValidQual AvsLicenceRollfeld)
|
E.where_ $ E.exists (hasValidQual AvsLicenceRollfeld)
|
||||||
E.&&. E.notExists (hasValidQual AvsLicenceVorfeld)
|
E.&&. E.notExists (hasValidQual AvsLicenceVorfeld)
|
||||||
return usr
|
return usr
|
||||||
@ -375,28 +375,5 @@ mkProblemLogTable = over _1 postprocess <$> dbTable validator DBTable{..}
|
|||||||
let usrSet = Map.keysSet . Map.filter id $ getDBFormResult (const False) usrMap
|
let usrSet = Map.keysSet . Map.filter id $ getDBFormResult (const False) usrMap
|
||||||
return (act, usrSet)
|
return (act, usrSet)
|
||||||
|
|
||||||
-- adminProblemCell :: IsDBTable m a => AdminProblem -> DBCell m a
|
-- adminProblemCell :: IsDBTable m a => AdminProblem -> DBCell m a -- moved to Handler.Utils
|
||||||
-- -- note that adminProblemCompany/adminProblemCompanyOld and adminProblemUser are automatically displayed within their own columns
|
-- msgAdminProblem :: AdminProblem -> DB (SomeMessages UniWorX) -- moved to Handler.Utils
|
||||||
-- adminProblemCell AdminProblemNewCompany{}
|
|
||||||
-- = i18nCell MsgAdminProblemNewCompany
|
|
||||||
-- adminProblemCell AdminProblemSupervisorNewCompany{adminProblemCompanyNew, adminProblemSupervisorReroute}
|
|
||||||
-- = i18nCell (MsgAdminProblemSupervisorNewCompany adminProblemSupervisorReroute) <> companyIdCell adminProblemCompanyNew
|
|
||||||
-- adminProblemCell AdminProblemSupervisorLeftCompany{adminProblemSupervisorReroute}
|
|
||||||
-- = i18nCell (MsgAdminProblemSupervisorLeftCompany adminProblemSupervisorReroute)
|
|
||||||
-- adminProblemCell AdminProblemNewlyUnsupervised{adminProblemCompanyNew}
|
|
||||||
-- = i18nCell MsgAdminProblemNewlyUnsupervised <> companyIdCell adminProblemCompanyNew
|
|
||||||
-- adminProblemCell AdminProblemUnknown{adminProblemText}
|
|
||||||
-- = textCell $ "Problem: " <> adminProblemText
|
|
||||||
|
|
||||||
|
|
||||||
-- msgAdminProblem :: AdminProblem -> DB (SomeMessages UniWorX)
|
|
||||||
-- msgAdminProblem AdminProblemNewCompany{adminProblemCompany=comp} = return $
|
|
||||||
-- SomeMessages [SomeMessage MsgAdminProblemNewCompany, text2message ": ", company2msg comp]
|
|
||||||
-- msgAdminProblem AdminProblemSupervisorNewCompany{adminProblemCompany=comp, adminProblemCompanyNew=newComp} = return $
|
|
||||||
-- SomeMessages [SomeMessage MsgAdminProblemSupervisorNewCompany, text2message ": ", company2msg comp, text2message " -> ", company2msg newComp]
|
|
||||||
-- msgAdminProblem AdminProblemSupervisorLeftCompany{adminProblemCompany=comp} = return $
|
|
||||||
-- SomeMessages [SomeMessage MsgAdminProblemSupervisorLeftCompany, text2message ": ", company2msg comp]
|
|
||||||
-- msgAdminProblem AdminProblemNewlyUnsupervised{adminProblemCompanyOld=comp, adminProblemCompanyNew=newComp} = return $
|
|
||||||
-- SomeMessages [SomeMessage MsgAdminProblemNewlyUnsupervised, text2message ": ", maybe (text2message "???") company2msg comp, text2message " -> ", company2msg newComp]
|
|
||||||
-- msgAdminProblem AdminProblemUnknown{adminProblemText=err} = return $
|
|
||||||
-- someMessages ["Problem: ", err]
|
|
||||||
|
|||||||
@ -150,47 +150,53 @@ reload r = getCurrentRoute >>= redirect . fromMaybe r
|
|||||||
|
|
||||||
-- | like `reload` to current route, but also preserving all GET parameters, using the current route, if known
|
-- | like `reload` to current route, but also preserving all GET parameters, using the current route, if known
|
||||||
reloadKeepGetParams :: (MonadHandler m, HandlerSite m ~ UniWorX) => Route (HandlerSite m) -> m a
|
reloadKeepGetParams :: (MonadHandler m, HandlerSite m ~ UniWorX) => Route (HandlerSite m) -> m a
|
||||||
reloadKeepGetParams r = liftHandler $ do
|
reloadKeepGetParams r = liftHandler $ do
|
||||||
getps <- reqGetParams <$> getRequest
|
getps <- reqGetParams <$> getRequest
|
||||||
route <- fromMaybe r <$> getCurrentRoute
|
route <- fromMaybe r <$> getCurrentRoute
|
||||||
-- addMessage Info $ toHtml (show getps) -- DEBUG ONLY
|
-- addMessage Info $ toHtml (show getps) -- DEBUG ONLY
|
||||||
-- RECALL: redirect GET parameters are used like so: -- redirect (UsersR, [("users-user-company","fraport")])
|
-- RECALL: redirect GET parameters are used like so: -- redirect (UsersR, [("users-user-company","fraport")])
|
||||||
redirect (route, getps)
|
redirect (route, getps)
|
||||||
|
|
||||||
-- | like `reloadKeepGetParams`, but always leading to the specific route instead of the current route
|
-- | like `reloadKeepGetParams`, but always leading to the specific route instead of the current route
|
||||||
redirectKeepGetParams :: (MonadHandler m, HandlerSite m ~ UniWorX) => Route (HandlerSite m) -> m a
|
redirectKeepGetParams :: (MonadHandler m, HandlerSite m ~ UniWorX) => Route (HandlerSite m) -> m a
|
||||||
redirectKeepGetParams route = liftHandler $ do
|
redirectKeepGetParams route = liftHandler $ do
|
||||||
getps <- reqGetParams <$> getRequest
|
getps <- reqGetParams <$> getRequest
|
||||||
redirect (route, getps)
|
redirect (route, getps)
|
||||||
|
|
||||||
|
|
||||||
adminProblemCell :: IsDBTable m a => AdminProblem -> DBCell m a
|
adminProblemCell :: (IsDBTable m a) => AdminProblem -> DBCell m a
|
||||||
-- note that adminProblemCompany/adminProblemCompanyOld and adminProblemUser are automatically displayed within their own columns
|
-- note that adminProblemCompany/adminProblemCompanyOld and adminProblemUser are automatically displayed within their own columns
|
||||||
adminProblemCell AdminProblemNewCompany{}
|
adminProblemCell AdminProblemNewCompany{}
|
||||||
= i18nCell MsgAdminProblemNewCompany
|
= i18nCell MsgAdminProblemNewCompany
|
||||||
adminProblemCell AdminProblemSupervisorNewCompany{adminProblemCompanyNew, adminProblemSupervisorReroute}
|
adminProblemCell AdminProblemSupervisorNewCompany{adminProblemCompanyNew, adminProblemSupervisorReroute}
|
||||||
= i18nCell (MsgAdminProblemSupervisorNewCompany adminProblemSupervisorReroute) <> companyIdCell adminProblemCompanyNew
|
= i18nCell (MsgAdminProblemSupervisorNewCompany adminProblemSupervisorReroute) <> companyIdCell adminProblemCompanyNew
|
||||||
adminProblemCell AdminProblemSupervisorLeftCompany{adminProblemSupervisorReroute}
|
adminProblemCell AdminProblemSupervisorLeftCompany{adminProblemSupervisorReroute}
|
||||||
= i18nCell (MsgAdminProblemSupervisorLeftCompany adminProblemSupervisorReroute)
|
= i18nCell (MsgAdminProblemSupervisorLeftCompany adminProblemSupervisorReroute)
|
||||||
adminProblemCell AdminProblemNewlyUnsupervised{adminProblemCompanyNew}
|
adminProblemCell AdminProblemCompanySuperiorChange{adminProblemUserOld=Nothing}
|
||||||
|
= i18nCell MsgAdminProblemCompanySuperiorChange
|
||||||
|
adminProblemCell AdminProblemCompanySuperiorChange{adminProblemUserOld=Just uid}
|
||||||
|
= i18nCell MsgAdminProblemCompanySuperiorChange <> spacerCell <> i18nCell MsgAdminProblemCompanySuperiorPrevious <> anchorCellM (AdminUserR <$> encrypt uid) (userIdWidget uid)
|
||||||
|
adminProblemCell AdminProblemNewlyUnsupervised{adminProblemCompanyNew}
|
||||||
= i18nCell MsgAdminProblemNewlyUnsupervised <> companyIdCell adminProblemCompanyNew
|
= i18nCell MsgAdminProblemNewlyUnsupervised <> companyIdCell adminProblemCompanyNew
|
||||||
adminProblemCell AdminProblemUnknown{adminProblemText}
|
adminProblemCell AdminProblemUnknown{adminProblemText}
|
||||||
= textCell $ "Problem: " <> adminProblemText
|
= textCell $ "Problem: " <> adminProblemText
|
||||||
|
|
||||||
company2msg :: CompanyId -> SomeMessage UniWorX
|
company2msg :: CompanyId -> SomeMessage UniWorX
|
||||||
company2msg = text2message . ciOriginal . unCompanyKey
|
company2msg = text2message . ciOriginal . unCompanyKey
|
||||||
|
|
||||||
msgAdminProblem :: AdminProblem -> DB (SomeMessages UniWorX)
|
msgAdminProblem :: AdminProblem -> DB (SomeMessages UniWorX)
|
||||||
msgAdminProblem AdminProblemNewCompany{adminProblemCompany=comp} = return $
|
msgAdminProblem AdminProblemNewCompany{adminProblemCompany=comp} = return $
|
||||||
SomeMessages [SomeMessage MsgAdminProblemNewCompany, text2message ": ", company2msg comp]
|
SomeMessages [SomeMessage MsgAdminProblemNewCompany, text2message ": ", company2msg comp]
|
||||||
msgAdminProblem AdminProblemSupervisorNewCompany{adminProblemCompany=comp, adminProblemCompanyNew=newComp, adminProblemSupervisorReroute=rer} = return $
|
msgAdminProblem AdminProblemSupervisorNewCompany{adminProblemCompany=comp, adminProblemCompanyNew=newComp, adminProblemSupervisorReroute=rer} = return $
|
||||||
SomeMessages [SomeMessage $ MsgAdminProblemSupervisorNewCompany rer, text2message ": ", company2msg comp, text2message " -> ", company2msg newComp]
|
SomeMessages [SomeMessage $ MsgAdminProblemSupervisorNewCompany rer, text2message ": ", company2msg comp, text2message " -> ", company2msg newComp]
|
||||||
msgAdminProblem AdminProblemSupervisorLeftCompany{adminProblemCompany=comp, adminProblemSupervisorReroute=rer} = return $
|
msgAdminProblem AdminProblemSupervisorLeftCompany{adminProblemCompany=comp, adminProblemSupervisorReroute=rer} = return $
|
||||||
SomeMessages [SomeMessage $ MsgAdminProblemSupervisorLeftCompany rer, text2message ": ", company2msg comp]
|
SomeMessages [SomeMessage $ MsgAdminProblemSupervisorLeftCompany rer, text2message ": ", company2msg comp]
|
||||||
msgAdminProblem AdminProblemNewlyUnsupervised{adminProblemCompanyOld=comp, adminProblemCompanyNew=newComp} = return $
|
msgAdminProblem AdminProblemCompanySuperiorChange{adminProblemCompany=comp} = return $
|
||||||
|
SomeMessages [SomeMessage $ MsgAdminProblemCompanySuperiorChange, text2message ": ", company2msg comp]
|
||||||
|
msgAdminProblem AdminProblemNewlyUnsupervised{adminProblemCompanyOld=comp, adminProblemCompanyNew=newComp} = return $
|
||||||
SomeMessages [SomeMessage MsgAdminProblemNewlyUnsupervised, text2message ": ", maybe (text2message "???") company2msg comp, text2message " -> ", company2msg newComp]
|
SomeMessages [SomeMessage MsgAdminProblemNewlyUnsupervised, text2message ": ", maybe (text2message "???") company2msg comp, text2message " -> ", company2msg newComp]
|
||||||
msgAdminProblem AdminProblemUnknown{adminProblemText=err} = return $
|
msgAdminProblem AdminProblemUnknown{adminProblemText=err} = return $
|
||||||
someMessages ["Problem: ", err]
|
someMessages ["Problem: ", err]
|
||||||
|
|
||||||
updateAutomatic :: Bool -> Widget
|
updateAutomatic :: Bool -> Widget
|
||||||
-- updateAutomatic = iconTooltip [whamlet|_{MsgNoAutomaticUpdateTip}|] (Just IconLocked)
|
-- updateAutomatic = iconTooltip [whamlet|_{MsgNoAutomaticUpdateTip}|] (Just IconLocked)
|
||||||
@ -198,4 +204,3 @@ updateAutomatic True = mempty
|
|||||||
updateAutomatic False = do
|
updateAutomatic False = do
|
||||||
msg <- messageIconI Warning IconLocked MsgNoAutomaticUpdateTip
|
msg <- messageIconI Warning IconLocked MsgNoAutomaticUpdateTip
|
||||||
messageTooltip msg
|
messageTooltip msg
|
||||||
|
|
||||||
@ -14,7 +14,7 @@ module Handler.Utils.Avs
|
|||||||
, upsertAvsUserById
|
, upsertAvsUserById
|
||||||
, updateAvsUserByIds
|
, updateAvsUserByIds
|
||||||
, linktoAvsUserByUIDs
|
, linktoAvsUserByUIDs
|
||||||
, queueAvsUpdateByUID, queueAvsUpdateByAID
|
, queueAvsUpdateByUID, queueAvsUpdateByAID
|
||||||
-- , getLicence, getLicenceDB, getLicenceByAvsId -- not supported by interface
|
-- , getLicence, getLicenceDB, getLicenceByAvsId -- not supported by interface
|
||||||
, AvsLicenceDifferences(..)
|
, AvsLicenceDifferences(..)
|
||||||
, setLicence, setLicenceAvs, setLicencesAvs
|
, setLicence, setLicenceAvs, setLicencesAvs
|
||||||
@ -26,9 +26,9 @@ module Handler.Utils.Avs
|
|||||||
, AvsException(..)
|
, AvsException(..)
|
||||||
, updateReceivers
|
, updateReceivers
|
||||||
, AvsPersonIdMapPersonCard
|
, AvsPersonIdMapPersonCard
|
||||||
-- CR3
|
-- CR3
|
||||||
, SomeAvsQuery(..)
|
, SomeAvsQuery(..)
|
||||||
, queryAvsCardNo, queryAvsCardNos
|
, queryAvsCardNo, queryAvsCardNos
|
||||||
) where
|
) where
|
||||||
|
|
||||||
import Import
|
import Import
|
||||||
@ -106,14 +106,14 @@ catchAll2log = voidMaybe $ catchAVShandler True True False Nothing
|
|||||||
catchAVShandler :: (MonadHandler m, MonadCatch m, RenderMessage (HandlerSite m) AvsException) => Bool -> Bool -> Bool -> a -> m a -> m a
|
catchAVShandler :: (MonadHandler m, MonadCatch m, RenderMessage (HandlerSite m) AvsException) => Bool -> Bool -> Bool -> a -> m a -> m a
|
||||||
catchAVShandler allEx toLog toMsg dft act = act `catches` (avsHandlers <> allHandlers)
|
catchAVShandler allEx toLog toMsg dft act = act `catches` (avsHandlers <> allHandlers)
|
||||||
where
|
where
|
||||||
avsHandlers =
|
avsHandlers =
|
||||||
[ Catch.Handler (\(exc::AvsException) -> liftHandler $ do
|
[ Catch.Handler (\(exc::AvsException) -> liftHandler $ do
|
||||||
let txt = "AVS exception ignored: " <> tshow exc
|
let txt = "AVS exception ignored: " <> tshow exc
|
||||||
when toLog $ $logErrorS "AVS" txt
|
when toLog $ $logErrorS "AVS" txt
|
||||||
when toMsg $ addMessageI Warning exc
|
when toMsg $ addMessageI Warning exc
|
||||||
return dft
|
return dft
|
||||||
)
|
)
|
||||||
|
|
||||||
, Catch.Handler (\(exc::ClientError ) -> liftHandler $ do
|
, Catch.Handler (\(exc::ClientError ) -> liftHandler $ do
|
||||||
let txt = "AVS fatal communicaton failure: " <> tshow exc
|
let txt = "AVS fatal communicaton failure: " <> tshow exc
|
||||||
when toLog $ $logErrorS "AVS" txt
|
when toLog $ $logErrorS "AVS" txt
|
||||||
@ -139,8 +139,8 @@ catchAVShandler allEx toLog toMsg dft act = act `catches` (avsHandlers <> allHan
|
|||||||
-- convenience wrapper for easy replacement with true status query
|
-- convenience wrapper for easy replacement with true status query
|
||||||
queryAvsFullStatus :: ( MonadThrow m, MonadHandler m, HandlerSite m ~ UniWorX ) => AvsPersonId -> m AvsResponseStatus
|
queryAvsFullStatus :: ( MonadThrow m, MonadHandler m, HandlerSite m ~ UniWorX ) => AvsPersonId -> m AvsResponseStatus
|
||||||
queryAvsFullStatus api =
|
queryAvsFullStatus api =
|
||||||
lookupAvsUser api <&> \case
|
lookupAvsUser api <&> \case
|
||||||
Just AvsDataPerson{avsPersonPersonCards=cards}
|
Just AvsDataPerson{avsPersonPersonCards=cards}
|
||||||
| notNull cards -> AvsResponseStatus $ Set.singleton $ AvsStatusPerson api cards
|
| notNull cards -> AvsResponseStatus $ Set.singleton $ AvsStatusPerson api cards
|
||||||
_otherwise -> AvsResponseStatus mempty
|
_otherwise -> AvsResponseStatus mempty
|
||||||
|
|
||||||
@ -158,7 +158,7 @@ lookupAvsUser api = Map.lookup api <$> lookupAvsUsers (Set.singleton api)
|
|||||||
-- Does not write to our own DB!
|
-- Does not write to our own DB!
|
||||||
lookupAvsUsers :: ( MonadThrow m, MonadHandler m, HandlerSite m ~ UniWorX ) =>
|
lookupAvsUsers :: ( MonadThrow m, MonadHandler m, HandlerSite m ~ UniWorX ) =>
|
||||||
Set AvsPersonId -> m (Map AvsPersonId AvsDataPerson)
|
Set AvsPersonId -> m (Map AvsPersonId AvsDataPerson)
|
||||||
lookupAvsUsers apis = do
|
lookupAvsUsers apis = do
|
||||||
AvsResponseStatus statuses <- avsQuery $ AvsQueryStatus apis
|
AvsResponseStatus statuses <- avsQuery $ AvsQueryStatus apis
|
||||||
let forFoldlM = $(permuteFun [3,2,1]) foldlM
|
let forFoldlM = $(permuteFun [3,2,1]) foldlM
|
||||||
forFoldlM statuses mempty $ \acc1 AvsStatusPerson{avsStatusPersonCardStatus=cards} ->
|
forFoldlM statuses mempty $ \acc1 AvsStatusPerson{avsStatusPersonCardStatus=cards} ->
|
||||||
@ -171,15 +171,15 @@ lookupAvsUsers apis = do
|
|||||||
updateReceivers :: UserId -> Handler (Entity User, [Entity User], Bool)
|
updateReceivers :: UserId -> Handler (Entity User, [Entity User], Bool)
|
||||||
updateReceivers uid = do
|
updateReceivers uid = do
|
||||||
-- First perform AVS update for receiver
|
-- First perform AVS update for receiver
|
||||||
runDB (getBy (UniqueUserAvsUser uid)) >>= \case
|
runDB (getBy (UniqueUserAvsUser uid)) >>= \case
|
||||||
Just Entity{entityVal=UserAvs{userAvsPersonId = apid}} -> catchAll2log $ upsertAvsUserById apid
|
Just Entity{entityVal=UserAvs{userAvsPersonId = apid}} -> catchAll2log $ upsertAvsUserById apid
|
||||||
Nothing -> return ()
|
Nothing -> return ()
|
||||||
-- Retrieve updated user and supervisors now
|
-- Retrieve updated user and supervisors now
|
||||||
(underling :: Entity User, avsSupers :: [(E.Value UserId, E.Value (Maybe AvsPersonId))]) <- runDB $ (,)
|
(underling :: Entity User, avsSupers :: [(E.Value UserId, E.Value (Maybe AvsPersonId))]) <- runDB $ (,)
|
||||||
<$> getJustEntity uid
|
<$> getJustEntity uid
|
||||||
<*> (E.select $ do
|
<*> (E.select $ do
|
||||||
(usrSuper :& usrAvs) <-
|
(usrSuper :& usrAvs) <-
|
||||||
E.from $ E.table @UserSupervisor
|
E.from $ E.table @UserSupervisor
|
||||||
`E.leftJoin` E.table @UserAvs
|
`E.leftJoin` E.table @UserAvs
|
||||||
`E.on` (\(usrSuper :& userAvs) -> usrSuper E.^. UserSupervisorSupervisor E.=?. userAvs E.?. UserAvsUser)
|
`E.on` (\(usrSuper :& userAvs) -> usrSuper E.^. UserSupervisorSupervisor E.=?. userAvs E.?. UserAvsUser)
|
||||||
E.where_ $ (usrSuper E.^. UserSupervisorUser E.==. E.val uid)
|
E.where_ $ (usrSuper E.^. UserSupervisorUser E.==. E.val uid)
|
||||||
@ -187,13 +187,13 @@ updateReceivers uid = do
|
|||||||
pure (usrSuper E.^. UserSupervisorSupervisor, usrAvs E.?. UserAvsPersonId)
|
pure (usrSuper E.^. UserSupervisorSupervisor, usrAvs E.?. UserAvsPersonId)
|
||||||
)
|
)
|
||||||
let (superVs, avsIds) = unzip avsSupers
|
let (superVs, avsIds) = unzip avsSupers
|
||||||
receiverIDs :: [UserId] = E.unValue <$> superVs
|
receiverIDs :: [UserId] = E.unValue <$> superVs
|
||||||
toUpdate = Set.fromList $ mapMaybe E.unValue avsIds
|
toUpdate = Set.fromList $ mapMaybe E.unValue avsIds
|
||||||
directResult = return (underling, pure underling, True) -- already contains updated address
|
directResult = return (underling, pure underling, True) -- already contains updated address
|
||||||
forM_ toUpdate (catchAll2log . upsertAvsUserById) -- attempt to update postaddress from AVS
|
forM_ toUpdate (catchAll2log . upsertAvsUserById) -- attempt to update postaddress from AVS
|
||||||
if null receiverIDs
|
if null receiverIDs
|
||||||
then directResult
|
then directResult
|
||||||
else do
|
else do
|
||||||
receivers <- runDB $ selectList [UserId <-. receiverIDs] [] -- due to possible address updates, we must runDB once more and cannot join above
|
receivers <- runDB $ selectList [UserId <-. receiverIDs] [] -- due to possible address updates, we must runDB once more and cannot join above
|
||||||
if null receivers
|
if null receivers
|
||||||
then directResult
|
then directResult
|
||||||
@ -205,8 +205,8 @@ updateReceivers uid = do
|
|||||||
|
|
||||||
|
|
||||||
-- | `SomeAvsQuery` is an umbrella to unify usage of all AVS queries, since Servant required separate types to fit the existing AVS-VSM API
|
-- | `SomeAvsQuery` is an umbrella to unify usage of all AVS queries, since Servant required separate types to fit the existing AVS-VSM API
|
||||||
class SomeAvsQuery q where
|
class SomeAvsQuery q where
|
||||||
type SomeAvsResponse q :: Type
|
type SomeAvsResponse q :: Type
|
||||||
pickQuery :: (MonadIO m) => AvsQuery -> q -> m (Either ClientError (SomeAvsResponse q))
|
pickQuery :: (MonadIO m) => AvsQuery -> q -> m (Either ClientError (SomeAvsResponse q))
|
||||||
-- | send query to AVS or maybe look it up within cache, depending on the type of the query
|
-- | send query to AVS or maybe look it up within cache, depending on the type of the query
|
||||||
avsQuery :: (MonadHandler m, HandlerSite m ~ UniWorX, MonadThrow m) => q -> m (SomeAvsResponse q)
|
avsQuery :: (MonadHandler m, HandlerSite m ~ UniWorX, MonadThrow m) => q -> m (SomeAvsResponse q)
|
||||||
@ -217,13 +217,13 @@ class SomeAvsQuery q where
|
|||||||
|
|
||||||
avsQueryNoCacheDefault :: (SomeAvsQuery q
|
avsQueryNoCacheDefault :: (SomeAvsQuery q
|
||||||
, MonadHandler m, HandlerSite m ~ UniWorX, MonadThrow m) => q -> m (SomeAvsResponse q)
|
, MonadHandler m, HandlerSite m ~ UniWorX, MonadThrow m) => q -> m (SomeAvsResponse q)
|
||||||
avsQueryNoCacheDefault qry = do
|
avsQueryNoCacheDefault qry = do
|
||||||
qfun <- maybeThrowM AvsInterfaceUnavailable $ getsYesod $ preview (_appAvsQuery . _Just . to pickQuery)
|
qfun <- maybeThrowM AvsInterfaceUnavailable $ getsYesod $ preview (_appAvsQuery . _Just . to pickQuery)
|
||||||
throwLeftM $ qfun qry
|
throwLeftM $ qfun qry
|
||||||
|
|
||||||
avsQueryCached :: (SomeAvsQuery q, Binary q, Binary (SomeAvsResponse q), Typeable (SomeAvsResponse q), NFData (SomeAvsResponse q)
|
avsQueryCached :: (SomeAvsQuery q, Binary q, Binary (SomeAvsResponse q), Typeable (SomeAvsResponse q), NFData (SomeAvsResponse q)
|
||||||
, MonadHandler m, HandlerSite m ~ UniWorX, MonadThrow m) => q -> m (SomeAvsResponse q)
|
, MonadHandler m, HandlerSite m ~ UniWorX, MonadThrow m) => q -> m (SomeAvsResponse q)
|
||||||
avsQueryCached qry =
|
avsQueryCached qry =
|
||||||
getsYesod (preview $ _appAvsConf . _Just . _avsCacheExpiry) >>= \case
|
getsYesod (preview $ _appAvsConf . _Just . _avsCacheExpiry) >>= \case
|
||||||
Just t | t > 1 -> memcachedBy (Just $ Right t) qry $ avsQueryNoCache qry
|
Just t | t > 1 -> memcachedBy (Just $ Right t) qry $ avsQueryNoCache qry
|
||||||
_ -> avsQueryNoCache qry
|
_ -> avsQueryNoCache qry
|
||||||
@ -232,7 +232,7 @@ instance SomeAvsQuery AvsQueryPerson where
|
|||||||
type SomeAvsResponse AvsQueryPerson = AvsResponsePerson
|
type SomeAvsResponse AvsQueryPerson = AvsResponsePerson
|
||||||
pickQuery = avsQueryPerson
|
pickQuery = avsQueryPerson
|
||||||
avsQuery = avsQueryCached
|
avsQuery = avsQueryCached
|
||||||
|
|
||||||
instance SomeAvsQuery AvsQueryStatus where
|
instance SomeAvsQuery AvsQueryStatus where
|
||||||
type SomeAvsResponse AvsQueryStatus = AvsResponseStatus
|
type SomeAvsResponse AvsQueryStatus = AvsResponseStatus
|
||||||
pickQuery = avsQueryStatus
|
pickQuery = avsQueryStatus
|
||||||
@ -246,24 +246,24 @@ instance SomeAvsQuery AvsQueryContact where
|
|||||||
instance SomeAvsQuery AvsQuerySetLicences where
|
instance SomeAvsQuery AvsQuerySetLicences where
|
||||||
type SomeAvsResponse AvsQuerySetLicences = AvsResponseSetLicences
|
type SomeAvsResponse AvsQuerySetLicences = AvsResponseSetLicences
|
||||||
pickQuery = avsQuerySetLicences
|
pickQuery = avsQuerySetLicences
|
||||||
-- NOTE: avsQuery = avsQueryCached -- should not and indeed does not compile
|
-- NOTE: avsQuery = avsQueryCached -- should not and indeed does not compile
|
||||||
avsQueryNoCache qry = avsQueryNoCacheDefault qry
|
avsQueryNoCache qry = avsQueryNoCacheDefault qry
|
||||||
<* memcachedInvalidate (Proxy @AvsResponseContact) -- invalidate all AvsResponseContact which may contain RampLicence info, since keys may comprise several ids
|
<* memcachedInvalidate (Proxy @AvsResponseContact) -- invalidate all AvsResponseContact which may contain RampLicence info, since keys may comprise several ids
|
||||||
|
|
||||||
instance SomeAvsQuery AvsQueryGetAllLicences where
|
instance SomeAvsQuery AvsQueryGetAllLicences where
|
||||||
type SomeAvsResponse AvsQueryGetAllLicences = AvsResponseGetLicences
|
type SomeAvsResponse AvsQueryGetAllLicences = AvsResponseGetLicences
|
||||||
pickQuery = const . avsQueryGetAllLicences
|
pickQuery = const . avsQueryGetAllLicences
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
queryAvsCardNos :: Foldable t => t (Either AvsCardNo AvsFullCardNo) -> Handler (Set AvsPersonId)
|
queryAvsCardNos :: Foldable t => t (Either AvsCardNo AvsFullCardNo) -> Handler (Set AvsPersonId)
|
||||||
queryAvsCardNos = foldMapM queryAvsCardNo
|
queryAvsCardNos = foldMapM queryAvsCardNo
|
||||||
|
|
||||||
queryAvsCardNo :: Either AvsCardNo AvsFullCardNo -> Handler (Set AvsPersonId)
|
queryAvsCardNo :: Either AvsCardNo AvsFullCardNo -> Handler (Set AvsPersonId)
|
||||||
queryAvsCardNo crd = do
|
queryAvsCardNo crd = do
|
||||||
AvsResponsePerson adps <- avsQuery $ qry crd
|
AvsResponsePerson adps <- avsQuery $ qry crd
|
||||||
return $ Set.map avsPersonPersonID adps
|
return $ Set.map avsPersonPersonID adps
|
||||||
where
|
where
|
||||||
qry (Left acno) = def{ avsPersonQueryCardNo = Just acno }
|
qry (Left acno) = def{ avsPersonQueryCardNo = Just acno }
|
||||||
qry (Right AvsFullCardNo{..}) = def{ avsPersonQueryCardNo = Just avsFullCardNo
|
qry (Right AvsFullCardNo{..}) = def{ avsPersonQueryCardNo = Just avsFullCardNo
|
||||||
, avsPersonQueryVersionNo = Just avsFullCardVersion
|
, avsPersonQueryVersionNo = Just avsFullCardVersion
|
||||||
@ -271,7 +271,7 @@ queryAvsCardNo crd = do
|
|||||||
|
|
||||||
-- | Queries AVS Status to retrieve primary card (heursitic)
|
-- | Queries AVS Status to retrieve primary card (heursitic)
|
||||||
queryAvsPrimaryCard :: (MonadHandler m, HandlerSite m ~ UniWorX, MonadCatch m) => AvsPersonId -> m (Maybe AvsDataPersonCard)
|
queryAvsPrimaryCard :: (MonadHandler m, HandlerSite m ~ UniWorX, MonadCatch m) => AvsPersonId -> m (Maybe AvsDataPersonCard)
|
||||||
queryAvsPrimaryCard api = runMaybeT $ do
|
queryAvsPrimaryCard api = runMaybeT $ do
|
||||||
AvsResponseStatus res <- MaybeT . catchAVS2log . fmap Just . avsQuery . AvsQueryStatus $ Set.singleton api
|
AvsResponseStatus res <- MaybeT . catchAVS2log . fmap Just . avsQuery . AvsQueryStatus $ Set.singleton api
|
||||||
pstatus <- hoistMaybe $ Set.lookupMax $ Set.filter ((api ==) . avsStatusPersonID) res
|
pstatus <- hoistMaybe $ Set.lookupMax $ Set.filter ((api ==) . avsStatusPersonID) res
|
||||||
hoistMaybe $ Set.lookupMax $ avsStatusPersonCardStatus pstatus
|
hoistMaybe $ Set.lookupMax $ avsStatusPersonCardStatus pstatus
|
||||||
@ -285,7 +285,7 @@ queryAvsFullCardNo = fmap (fmap getFullCardNo) . queryAvsPrimaryCard
|
|||||||
|
|
||||||
-- | Like `updateAvsUserByIds`, but exceptions are not caught here to allow rollbacks
|
-- | Like `updateAvsUserByIds`, but exceptions are not caught here to allow rollbacks
|
||||||
updateAvsUserById :: AvsPersonId -> DB (Maybe UserId)
|
updateAvsUserById :: AvsPersonId -> DB (Maybe UserId)
|
||||||
updateAvsUserById apid = do
|
updateAvsUserById apid = do
|
||||||
AvsResponseContact adcs <- avsQuery $ AvsQueryContact $ Set.singleton $ AvsObjPersonId apid
|
AvsResponseContact adcs <- avsQuery $ AvsQueryContact $ Set.singleton $ AvsObjPersonId apid
|
||||||
let res = Set.filter ((== apid) . avsContactPersonID) adcs
|
let res = Set.filter ((== apid) . avsContactPersonID) adcs
|
||||||
snd <<$>> traverseJoin updateAvsUserByADC (Set.lookupMax res)
|
snd <<$>> traverseJoin updateAvsUserByADC (Set.lookupMax res)
|
||||||
@ -306,10 +306,10 @@ updateAvsUserByIds' apids = do
|
|||||||
now <- liftIO getCurrentTime
|
now <- liftIO getCurrentTime
|
||||||
runDB $ updateWhere [UserAvsPersonId <-. missing] [UserAvsLastSynch =. now, UserAvsLastSynchError =. Just "Avs contact info unknown for AvsPersonId"] -- all others were already marked as updated
|
runDB $ updateWhere [UserAvsPersonId <-. missing] [UserAvsLastSynch =. now, UserAvsLastSynchError =. Just "Avs contact info unknown for AvsPersonId"] -- all others were already marked as updated
|
||||||
return oks
|
return oks
|
||||||
where
|
where
|
||||||
procResp :: (Set (AvsPersonId, UserId), Set AvsPersonId) -> AvsDataContact -> Handler (Set (AvsPersonId, UserId), Set AvsPersonId)
|
procResp :: (Set (AvsPersonId, UserId), Set AvsPersonId) -> AvsDataContact -> Handler (Set (AvsPersonId, UserId), Set AvsPersonId)
|
||||||
procResp (accOk, accBad) adc = do
|
procResp (accOk, accBad) adc = do
|
||||||
let errHandler e = runDB $ do
|
let errHandler e = runDB $ do
|
||||||
let apid = avsContactPersonID adc
|
let apid = avsContactPersonID adc
|
||||||
now <- liftIO getCurrentTime
|
now <- liftIO getCurrentTime
|
||||||
updateBy (UniqueUserAvsId apid) [UserAvsLastSynch =. now, UserAvsLastSynchError =. Just (tshow e)]
|
updateBy (UniqueUserAvsId apid) [UserAvsLastSynch =. now, UserAvsLastSynchError =. Just (tshow e)]
|
||||||
@ -319,19 +319,19 @@ updateAvsUserByIds' apids = do
|
|||||||
res <- updateAvsUserByADC adc
|
res <- updateAvsUserByADC adc
|
||||||
return (maybeInsert res accOk, accBad)
|
return (maybeInsert res accOk, accBad)
|
||||||
catchAll (runDB updateAvsUserByADC') errHandler
|
catchAll (runDB updateAvsUserByADC') errHandler
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
updateAvsUserByADC :: AvsDataContact -> DB (Maybe (AvsPersonId, UserId))
|
updateAvsUserByADC :: AvsDataContact -> DB (Maybe (AvsPersonId, UserId))
|
||||||
updateAvsUserByADC newAvsDataContact@(AvsDataContact apid newAvsPersonInfo newAvsFirmInfo) = runMaybeT $ do
|
updateAvsUserByADC newAvsDataContact@(AvsDataContact apid newAvsPersonInfo newAvsFirmInfo) = runMaybeT $ do
|
||||||
(Entity uaId usravs) <- MaybeT $ getBy $ UniqueUserAvsId apid
|
(Entity uaId usravs) <- MaybeT $ getBy $ UniqueUserAvsId apid
|
||||||
let usrId = userAvsUser usravs
|
let usrId = userAvsUser usravs
|
||||||
usr <- MaybeT $ get usrId
|
usr <- MaybeT $ get usrId
|
||||||
lift $ do -- maybeT no longer needed from here onwards
|
lift $ do -- maybeT no longer needed from here onwards
|
||||||
let oldAvsPersonInfo = userAvsLastPersonInfo usravs -- Nothing is ok here
|
let oldAvsPersonInfo = userAvsLastPersonInfo usravs -- Nothing is ok here
|
||||||
oldAvsFirmInfo = userAvsLastFirmInfo usravs -- Nothing is ok here
|
oldAvsFirmInfo = userAvsLastFirmInfo usravs -- Nothing is ok here
|
||||||
oldAvsCardNo = userAvsLastCardNo usravs & fmap Just
|
oldAvsCardNo = userAvsLastCardNo usravs & fmap Just
|
||||||
oldAvsDataContact = case (oldAvsPersonInfo, oldAvsFirmInfo) of
|
oldAvsDataContact = case (oldAvsPersonInfo, oldAvsFirmInfo) of
|
||||||
(Just oapi, Just oafi) -> Just $ AvsDataContact apid oapi oafi
|
(Just oapi, Just oafi) -> Just $ AvsDataContact apid oapi oafi
|
||||||
_ -> Nothing
|
_ -> Nothing
|
||||||
newAvsCardNo <- queryAvsFullCardNo apid -- Nothing os ok here, does not throw
|
newAvsCardNo <- queryAvsFullCardNo apid -- Nothing os ok here, does not throw
|
||||||
@ -339,10 +339,10 @@ updateAvsUserByADC newAvsDataContact@(AvsDataContact apid newAvsPersonInfo newAv
|
|||||||
mbLdapExpire <- getsYesod $ views appSettings appSynchroniseLdapUsersExpire
|
mbLdapExpire <- getsYesod $ views appSettings appSynchroniseLdapUsersExpire
|
||||||
ldap_ups <- if | Just ldapExpire <- mbLdapExpire
|
ldap_ups <- if | Just ldapExpire <- mbLdapExpire
|
||||||
, maybe True (\lastLdapSync -> now > addUTCTime ldapExpire lastLdapSync) (userLastLdapSynchronisation usr)
|
, maybe True (\lastLdapSync -> now > addUTCTime ldapExpire lastLdapSync) (userLastLdapSynchronisation usr)
|
||||||
, Just udep <- userCompanyDepartment usr
|
, Just udep <- userCompanyDepartment usr
|
||||||
, let aipn = newAvsPersonInfo ^? _avsInfoInternalPersonalNo . _Just . _avsInternalPersonalNo
|
, let aipn = newAvsPersonInfo ^? _avsInfoInternalPersonalNo . _Just . _avsInternalPersonalNo
|
||||||
depKey = CompanyKey $ stripCI udep -- Shorthand is returned by LDAP
|
depKey = CompanyKey $ stripCI udep -- Shorthand is returned by LDAP
|
||||||
-> do -- LDAP sync invalid/expired
|
-> do -- LDAP sync invalid/expired
|
||||||
usrComp <- getBy $ UniqueUserCompany usrId depKey
|
usrComp <- getBy $ UniqueUserCompany usrId depKey
|
||||||
whenIsJust usrComp $ \Entity{entityKey=ucKey, entityVal=UserCompany{userCompanySupervisor=isSuper, userCompanySupervisorReroute=rroute}} -> do
|
whenIsJust usrComp $ \Entity{entityKey=ucKey, entityVal=UserCompany{userCompanySupervisor=isSuper, userCompanySupervisorReroute=rroute}} -> do
|
||||||
delete ucKey
|
delete ucKey
|
||||||
@ -358,7 +358,7 @@ updateAvsUserByADC newAvsDataContact@(AvsDataContact apid newAvsPersonInfo newAv
|
|||||||
[mkCheckUpdate CU_API_UserCompanyPersonalNumber]
|
[mkCheckUpdate CU_API_UserCompanyPersonalNumber]
|
||||||
let per_ups = mapMaybe (mkUpdate' usr newAvsPersonInfo oldAvsPersonInfo . mkCheckUpdate)
|
let per_ups = mapMaybe (mkUpdate' usr newAvsPersonInfo oldAvsPersonInfo . mkCheckUpdate)
|
||||||
[ CU_API_UserFirstName
|
[ CU_API_UserFirstName
|
||||||
, CU_API_UserSurname
|
, CU_API_UserSurname
|
||||||
, CU_API_UserDisplayName
|
, CU_API_UserDisplayName
|
||||||
, CU_API_UserBirthday
|
, CU_API_UserBirthday
|
||||||
, CU_API_UserMobile
|
, CU_API_UserMobile
|
||||||
@ -377,17 +377,17 @@ updateAvsUserByADC newAvsDataContact@(AvsDataContact apid newAvsPersonInfo newAv
|
|||||||
, UserAvsLastFirmInfo =. Just newAvsFirmInfo
|
, UserAvsLastFirmInfo =. Just newAvsFirmInfo
|
||||||
, UserAvsLastCardNo =. newAvsCardNo
|
, UserAvsLastCardNo =. newAvsCardNo
|
||||||
]
|
]
|
||||||
|
|
||||||
-- update company association & supervision
|
-- update company association & supervision
|
||||||
Entity{entityKey=newCompanyId} <- upsertAvsCompany newAvsFirmInfo oldAvsFirmInfo
|
Entity{entityKey=newCompanyId} <- upsertAvsCompany newAvsFirmInfo oldAvsFirmInfo
|
||||||
oldCompanyEnt <- getAvsCompany `traverseJoin` oldAvsFirmInfo
|
oldCompanyEnt <- getAvsCompany `traverseJoin` oldAvsFirmInfo
|
||||||
primaryCompanyId <- userCompanyCompany <<$>> getUserPrimaryCompany usrId
|
primaryCompanyId <- userCompanyCompany <<$>> getUserPrimaryCompany usrId
|
||||||
let oldCompanyId = entityKey <$> oldCompanyEnt
|
let oldCompanyId = entityKey <$> oldCompanyEnt
|
||||||
-- oldCompanyMb = entityVal <$> oldCompanyEnt
|
-- oldCompanyMb = entityVal <$> oldCompanyEnt
|
||||||
-- pst_up = if
|
-- pst_up = if
|
||||||
-- -- | isNothing oldCompanyMb || oldCompanyId == primaryCompanyId -- refactor could replace next 4 lines
|
-- -- | isNothing oldCompanyMb || oldCompanyId == primaryCompanyId -- refactor could replace next 4 lines
|
||||||
-- -- -> mkUpdate' usr newCompany oldCompanyMb $ CheckUpdate UserPrefersPostal _companyPrefersPostal -- always update if company association is fresh (case should not occur in practice though)
|
-- -- -> mkUpdate' usr newCompany oldCompanyMb $ CheckUpdate UserPrefersPostal _companyPrefersPostal -- always update if company association is fresh (case should not occur in practice though)
|
||||||
-- | isNothing oldCompanyMb
|
-- | isNothing oldCompanyMb
|
||||||
-- -> mkUpdateDirect usr newCompany $ CheckUpdate UserPrefersPostal _companyPrefersPostal -- always update if company association is fresh (case should not occur in practice though)
|
-- -> mkUpdateDirect usr newCompany $ CheckUpdate UserPrefersPostal _companyPrefersPostal -- always update if company association is fresh (case should not occur in practice though)
|
||||||
-- | oldCompanyId == primaryCompanyId -- && isJust oldCompanyId -- is ensured by previous line
|
-- | oldCompanyId == primaryCompanyId -- && isJust oldCompanyId -- is ensured by previous line
|
||||||
-- -> mkUpdate usr newCompany oldCompanyMb $ CheckUpdate UserPrefersPostal _companyPrefersPostal -- possibly change postal preference
|
-- -> mkUpdate usr newCompany oldCompanyMb $ CheckUpdate UserPrefersPostal _companyPrefersPostal -- possibly change postal preference
|
||||||
@ -395,38 +395,37 @@ updateAvsUserByADC newAvsDataContact@(AvsDataContact apid newAvsPersonInfo newAv
|
|||||||
-- -> Nothing
|
-- -> Nothing
|
||||||
superReasonComDef = tshow SupervisorReasonCompanyDefault
|
superReasonComDef = tshow SupervisorReasonCompanyDefault
|
||||||
newUserComp = UserCompany usrId newCompanyId False False 1 True -- default value for new company insertion, if no update can be done
|
newUserComp = UserCompany usrId newCompanyId False False 1 True -- default value for new company insertion, if no update can be done
|
||||||
|
|
||||||
|
|
||||||
usr_up2 <- case oldAvsFirmInfo of
|
usr_up2 <- case oldAvsFirmInfo of
|
||||||
_ | Just newCompanyId == oldCompanyId -- company unchanged entirely
|
_ | Just newCompanyId == oldCompanyId -- company unchanged entirely
|
||||||
-> return mempty -- => do nothing
|
-> return mempty -- => do nothing
|
||||||
(Just oafi) | isJust (view _avsFirmPostAddressSimple oafi)
|
(Just oafi) | isJust (view _avsFirmPostAddressSimple oafi)
|
||||||
&& ((==) `on` view _avsFirmPostAddressSimple) oafi newAvsFirmInfo -- non-empty company address unchanged OR
|
&& ((==) `on` view _avsFirmPostAddressSimple) oafi newAvsFirmInfo -- non-empty company address unchanged OR
|
||||||
|| isJust (view _avsFirmPrimaryEmail oafi)
|
|| isJust (view _avsFirmPrimaryEmail oafi)
|
||||||
&& ((==) `on` view _avsFirmPrimaryEmail) oafi newAvsFirmInfo -- non-empty company primary email unchanged
|
&& ((==) `on` view _avsFirmPrimaryEmail) oafi newAvsFirmInfo -- non-empty company primary email unchanged
|
||||||
-> do -- => just update user company association, keeping supervision privileges
|
-> do -- => just update user company association, keeping supervision privileges
|
||||||
case oldCompanyId of
|
case oldCompanyId of
|
||||||
Nothing -> void $ insertUnique newUserComp -- it's ok if this already exists
|
Nothing -> void $ insertUnique newUserComp -- it's ok if this already exists
|
||||||
Just ocid -> do
|
Just ocid -> do
|
||||||
void $ upsertBySafe (UniqueUserCompany usrId ocid) newUserComp (_userCompanyCompany .~ newCompanyId) -- keep default supervisor settings
|
void $ upsertBySafe (UniqueUserCompany usrId ocid) newUserComp (_userCompanyCompany .~ newCompanyId) -- keep default supervisor settings
|
||||||
void $ updateWhere [ UserSupervisorSupervisor ==. usrId -- update company-related supervisions
|
void $ updateWhere [ UserSupervisorSupervisor ==. usrId -- update company-related supervisions
|
||||||
, UserSupervisorCompany ==. Just ocid -- to new company, regardless of
|
, UserSupervisorCompany ==. Just ocid -- to new company, regardless of
|
||||||
, UserSupervisorReason ==. Just superReasonComDef] -- user
|
, UserSupervisorReason ==. Just superReasonComDef] -- user
|
||||||
[ UserSupervisorCompany =. Just newCompanyId]
|
[ UserSupervisorCompany =. Just newCompanyId]
|
||||||
return mempty
|
return mempty
|
||||||
_ | Just newCompanyId == primaryCompanyId -- old primaryCompany is now also AVS-company
|
_ | Just newCompanyId == primaryCompanyId -- old primaryCompany is now also AVS-company
|
||||||
-> do
|
-> do
|
||||||
whenIsJust oldCompanyId $ \oldCid -> do
|
whenIsJust oldCompanyId $ \oldCid -> do
|
||||||
deleteBy $ UniqueUserCompany usrId oldCid
|
deleteBy $ UniqueUserCompany usrId oldCid
|
||||||
deleteWhere $ (UserSupervisorUser ==. usrId):(UserSupervisorCompany ==. oldCompanyId):(UserSupervisorReason ~=. superReasonComDef)
|
deleteWhere $ (UserSupervisorUser ==. usrId):(UserSupervisorCompany ==. oldCompanyId):(UserSupervisorReason ~=. superReasonComDef)
|
||||||
return mempty
|
return mempty
|
||||||
_ -- company changed completely
|
_ -- company changed completely
|
||||||
-> do
|
-> do
|
||||||
(pst_up, problems) <- switchAvsUserCompany False False usrId newCompanyId
|
(pst_up, problems) <- switchAvsUserCompany False False usrId newCompanyId
|
||||||
mapM_ reportAdminProblem problems
|
mapM_ reportAdminProblem problems
|
||||||
-- Following line does not type, hence additional parameter needed
|
-- Following line does not type, hence additional parameter needed
|
||||||
-- return [ u | u@Update{updateField=f} <- pst_up, f /= UserPostAddress ] -- already computed in frm_up above, duplicate update must be prevented (version above accounts for legacy updates)
|
-- return [ u | u@Update{updateField=f} <- pst_up, f /= UserPostAddress ] -- already computed in frm_up above, duplicate update must be prevented (version above accounts for legacy updates)
|
||||||
return pst_up
|
return pst_up
|
||||||
-- SPECIALISED CODE, PROBABLY DEPRECATED
|
-- SPECIALISED CODE, PROBABLY DEPRECATED
|
||||||
-- switch user company, keeping old priority
|
-- switch user company, keeping old priority
|
||||||
-- (getBy . UniqueUserCompany usrId) `traverseJoin` oldCompanyId >>= \case
|
-- (getBy . UniqueUserCompany usrId) `traverseJoin` oldCompanyId >>= \case
|
||||||
@ -443,8 +442,7 @@ updateAvsUserByADC newAvsDataContact@(AvsDataContact apid newAvsPersonInfo newAv
|
|||||||
-- addCompanySupervisors newCompanyId usrId
|
-- addCompanySupervisors newCompanyId usrId
|
||||||
-- newAPs <- count $ (UserSupervisorUser ==. usrId) : (UserSupervisorCompany ==. Just newCompanyId) : (UserSupervisorReason ~=. superReasonComDef)
|
-- newAPs <- count $ (UserSupervisorUser ==. usrId) : (UserSupervisorCompany ==. Just newCompanyId) : (UserSupervisorReason ~=. superReasonComDef)
|
||||||
-- when (oldAPs > 0 && newAPs <= 0) $ reportAdminProblem $ AdminProblemNewlyUnsupervised usrId oldCompanyId newCompanyId
|
-- when (oldAPs > 0 && newAPs <= 0) $ reportAdminProblem $ AdminProblemNewlyUnsupervised usrId oldCompanyId newCompanyId
|
||||||
-- return pst_up
|
-- return pst_up
|
||||||
repsertSuperiorSupervisor (Just newCompanyId) newAvsFirmInfo usrId -- ensure firmInfo superior is supervisor, must be executed after updating company default supervisors
|
|
||||||
update usrId $ usr_up2 <> usr_up1 -- update user eventually
|
update usrId $ usr_up2 <> usr_up1 -- update user eventually
|
||||||
update uaId avs_ups -- update stored avsinfo for future updates
|
update uaId avs_ups -- update stored avsinfo for future updates
|
||||||
return (apid, usrId)
|
return (apid, usrId)
|
||||||
@ -452,7 +450,7 @@ updateAvsUserByADC newAvsDataContact@(AvsDataContact apid newAvsPersonInfo newAv
|
|||||||
|
|
||||||
linktoAvsUserByUIDs :: Set UserId -> Handler ()
|
linktoAvsUserByUIDs :: Set UserId -> Handler ()
|
||||||
linktoAvsUserByUIDs uids = do
|
linktoAvsUserByUIDs uids = do
|
||||||
ips <- runDB $ E.select $ do
|
ips <- runDB $ E.select $ do
|
||||||
usr <- E.from $ E.table @User
|
usr <- E.from $ E.table @User
|
||||||
let uid = usr E.^. UserId
|
let uid = usr E.^. UserId
|
||||||
ipn = usr E.^. UserCompanyPersonalNumber
|
ipn = usr E.^. UserCompanyPersonalNumber
|
||||||
@ -463,8 +461,8 @@ linktoAvsUserByUIDs uids = do
|
|||||||
E.where_ $ uid E.==. usrAvs E.^. UserAvsUser
|
E.where_ $ uid E.==. usrAvs E.^. UserAvsUser
|
||||||
)
|
)
|
||||||
return (uid, ipn)
|
return (uid, ipn)
|
||||||
mapM_ procUsr ips
|
mapM_ procUsr ips
|
||||||
where
|
where
|
||||||
procUsr (E.Value uid, E.Value (Just ipn)) = catchAll2log $ linktoAvsUserByUID uid $ mkAvsInternalPersonalNo ipn
|
procUsr (E.Value uid, E.Value (Just ipn)) = catchAll2log $ linktoAvsUserByUID uid $ mkAvsInternalPersonalNo ipn
|
||||||
procUsr _ = return ()
|
procUsr _ = return ()
|
||||||
|
|
||||||
@ -481,7 +479,7 @@ linktoAvsUserByUID uid aipn = do
|
|||||||
-- createAvsUserById :: Set AvsPersonId -> Handler (Set (AvsPersonId, UserId)) ???
|
-- createAvsUserById :: Set AvsPersonId -> Handler (Set (AvsPersonId, UserId)) ???
|
||||||
-- | Create new user from AVS-Id. Will throw an AvsException if this is not possible, e.g. due to Uniqueness Constraints
|
-- | Create new user from AVS-Id. Will throw an AvsException if this is not possible, e.g. due to Uniqueness Constraints
|
||||||
createAvsUserById :: Maybe UserId -> AvsPersonId -> Handler UserId
|
createAvsUserById :: Maybe UserId -> AvsPersonId -> Handler UserId
|
||||||
createAvsUserById muid api = do
|
createAvsUserById muid api = do
|
||||||
AvsResponseContact contactRes <- avsQuery $ AvsQueryContact $ Set.singleton $ AvsObjPersonId api
|
AvsResponseContact contactRes <- avsQuery $ AvsQueryContact $ Set.singleton $ AvsObjPersonId api
|
||||||
case Set.toList contactRes of
|
case Set.toList contactRes of
|
||||||
[] -> throwM $ AvsUserUnknownByAvs api
|
[] -> throwM $ AvsUserUnknownByAvs api
|
||||||
@ -491,14 +489,14 @@ createAvsUserById muid api = do
|
|||||||
| otherwise -> do
|
| otherwise -> do
|
||||||
-- check for matching existing user
|
-- check for matching existing user
|
||||||
let internalPersNo :: Maybe Text = cpi ^? _avsInfoInternalPersonalNo . _Just . _avsInternalPersonalNo
|
let internalPersNo :: Maybe Text = cpi ^? _avsInfoInternalPersonalNo . _Just . _avsInternalPersonalNo
|
||||||
persMail :: Maybe UserEmail = cpi ^? _avsInfoPersonEMail . _Just . from _CI
|
persMail :: Maybe UserEmail = cpi ^? _avsInfoPersonEMail . _Just . from _CI
|
||||||
oldUsr <- runDB $ do
|
oldUsr <- runDB $ do
|
||||||
mbUid <- if isJust muid
|
mbUid <- if isJust muid
|
||||||
then return muid
|
then return muid
|
||||||
else firstJustM $ catMaybes
|
else firstJustM $ catMaybes
|
||||||
[ internalPersNo <&> (\ipn -> getKeyByFilter [UserCompanyPersonalNumber ==. Just ipn]) -- must ensure filter isnt ==. Nothing
|
[ internalPersNo <&> (\ipn -> getKeyByFilter [UserCompanyPersonalNumber ==. Just ipn]) -- must ensure filter isnt ==. Nothing
|
||||||
, persMail <&> guessUserByEmail
|
, persMail <&> guessUserByEmail
|
||||||
]
|
]
|
||||||
mbUAvs <- (getBy . UniqueUserAvsUser) `traverseJoin` mbUid
|
mbUAvs <- (getBy . UniqueUserAvsUser) `traverseJoin` mbUid
|
||||||
return (mbUid, mbUAvs)
|
return (mbUid, mbUAvs)
|
||||||
usrCardNo <- queryAvsFullCardNo api
|
usrCardNo <- queryAvsFullCardNo api
|
||||||
@ -512,11 +510,11 @@ createAvsUserById muid api = do
|
|||||||
, userAvsLastPersonInfo = mbPersonInfo
|
, userAvsLastPersonInfo = mbPersonInfo
|
||||||
, userAvsLastFirmInfo = mbFirmInfo
|
, userAvsLastFirmInfo = mbFirmInfo
|
||||||
, userAvsLastCardNo = mbUsrCardNo
|
, userAvsLastCardNo = mbUsrCardNo
|
||||||
}
|
}
|
||||||
case oldUsr of
|
case oldUsr of
|
||||||
(Nothing , Just _) -> throwM $ AvsUserUnknownByAvs api -- this case should never occur
|
(Nothing , Just _) -> throwM $ AvsUserUnknownByAvs api -- this case should never occur
|
||||||
(Just uid, Just Entity{entityVal=UserAvs{userAvsPersonId=api',userAvsUser=uid'}})
|
(Just uid, Just Entity{entityVal=UserAvs{userAvsPersonId=api',userAvsUser=uid'}})
|
||||||
| api /= api' -> throwM $ AvsIdMismatch api api'
|
| api /= api' -> throwM $ AvsIdMismatch api api'
|
||||||
| uid /= uid' -> throwM $ AvsUserAmbiguous api
|
| uid /= uid' -> throwM $ AvsUserAmbiguous api
|
||||||
| otherwise -> return uid -- nothing to do
|
| otherwise -> return uid -- nothing to do
|
||||||
(Just uid, Nothing) -> runDB $ do -- link with matching exisitng user
|
(Just uid, Nothing) -> runDB $ do -- link with matching exisitng user
|
||||||
@ -524,17 +522,17 @@ createAvsUserById muid api = do
|
|||||||
updRes <- updateAvsUserById api -- no loop, since updateAvsUserById does not call createAvsUserById
|
updRes <- updateAvsUserById api -- no loop, since updateAvsUserById does not call createAvsUserById
|
||||||
case updRes of
|
case updRes of
|
||||||
Nothing -> throwM $ AvsUserUnknownByAvs api
|
Nothing -> throwM $ AvsUserUnknownByAvs api
|
||||||
Just uid'
|
Just uid'
|
||||||
| uid /= uid' -> throwM $ AvsUserAmbiguous api
|
| uid /= uid' -> throwM $ AvsUserAmbiguous api
|
||||||
| otherwise -> return uid
|
| otherwise -> return uid
|
||||||
(Nothing, Nothing) -> do -- create fresh user
|
(Nothing, Nothing) -> do -- create fresh user
|
||||||
Entity{entityKey=cid, entityVal=cmp} <- runDB $ upsertAvsCompany firmInfo Nothing -- individual runDB, since no need to rollback
|
Entity{entityKey=cid, entityVal=cmp} <- runDB $ upsertAvsCompany firmInfo Nothing -- individual runDB, since no need to rollback
|
||||||
let pinPass = avsFullCardNo2pin <$> usrCardNo
|
let pinPass = avsFullCardNo2pin <$> usrCardNo
|
||||||
newUserData = AddUserData
|
newUserData = AddUserData
|
||||||
{ audTitle = Nothing
|
{ audTitle = Nothing
|
||||||
, audFirstName = cpi ^. _avsInfoFirstName & Text.strip
|
, audFirstName = cpi ^. _avsInfoFirstName & Text.strip
|
||||||
, audSurname = cpi ^. _avsInfoLastName & Text.strip
|
, audSurname = cpi ^. _avsInfoLastName & Text.strip
|
||||||
, audDisplayName = cpi ^. _avsInfoDisplayName
|
, audDisplayName = cpi ^. _avsInfoDisplayName
|
||||||
, audDisplayEmail = persMail & fromMaybe mempty
|
, audDisplayEmail = persMail & fromMaybe mempty
|
||||||
, audEmail = persMail & fromMaybe ("AVSNO:" <> cpi ^. _avsInfoPersonNo . from _CI)
|
, audEmail = persMail & fromMaybe ("AVSNO:" <> cpi ^. _avsInfoPersonNo . from _CI)
|
||||||
, audIdent = persMail & fromMaybe ("AVSID:" <> ciShow api )
|
, audIdent = persMail & fromMaybe ("AVSID:" <> ciShow api )
|
||||||
@ -542,74 +540,23 @@ createAvsUserById muid api = do
|
|||||||
, audMatriculation = cpi ^. _avsInfoPersonNo & Just . tshow
|
, audMatriculation = cpi ^. _avsInfoPersonNo & Just . tshow
|
||||||
, audSex = Nothing
|
, audSex = Nothing
|
||||||
, audBirthday = cpi ^. _avsInfoDateOfBirth
|
, audBirthday = cpi ^. _avsInfoDateOfBirth
|
||||||
, audMobile = cpi ^. _avsInfoPersonMobilePhoneNo
|
, audMobile = cpi ^. _avsInfoPersonMobilePhoneNo
|
||||||
, audTelephone = Nothing
|
, audTelephone = Nothing
|
||||||
, audFPersonalNumber = internalPersNo
|
, audFPersonalNumber = internalPersNo
|
||||||
, audFDepartment = toMaybe (isJust internalPersNo) (cmp ^. _companyShorthand . _CI)
|
, audFDepartment = toMaybe (isJust internalPersNo) (cmp ^. _companyShorthand . _CI)
|
||||||
, audPostAddress = Nothing -- always use company address indirectly
|
, audPostAddress = Nothing -- always use company address indirectly
|
||||||
, audPrefersPostal = cmp ^. _companyPrefersPostal
|
, audPrefersPostal = cmp ^. _companyPrefersPostal
|
||||||
, audPinPassword = pinPass
|
, audPinPassword = pinPass
|
||||||
}
|
}
|
||||||
runDB $ do -- any failure must rollback all DB write transactions here
|
runDB $ do -- any failure must rollback all DB write transactions here
|
||||||
uid <- maybeThrowM (AvsUserCreationFailed api) $ addNewUserDB newUserData
|
uid <- maybeThrowM (AvsUserCreationFailed api) $ addNewUserDB newUserData
|
||||||
let userComp = UserCompany uid cid False False 1 True -- default value for new company insertion, if no update can be done
|
let userComp = UserCompany uid cid False False 1 True -- default value for new company insertion, if no update can be done
|
||||||
void $ insertUnique userComp -- Nothing indicates that the user is already linked to the company (which is unlikely here)
|
void $ insertUnique userComp -- Nothing indicates that the user is already linked to the company (which is unlikely here)
|
||||||
-- Supervision
|
-- Supervision
|
||||||
addCompanySupervisors cid uid
|
addCompanySupervisors cid uid
|
||||||
repsertSuperiorSupervisor (Just cid) firmInfo uid
|
|
||||||
-- Save AVS data for future updates
|
-- Save AVS data for future updates
|
||||||
insert_ $ usrAvs uid (Just cpi) (Just firmInfo) usrCardNo -- unlikely that uid cannot be linked with avsid, but throw if it is not possible
|
insert_ $ usrAvs uid (Just cpi) (Just firmInfo) usrCardNo -- unlikely that uid cannot be linked with avsid, but throw if it is not possible
|
||||||
return uid
|
return uid
|
||||||
|
|
||||||
|
|
||||||
-- | upsert superior by eMail through LDAP only (currently no email search available in AVS)
|
|
||||||
repsertSuperiorSupervisor :: Maybe CompanyId -> AvsFirmInfo -> UserId -> DB ()
|
|
||||||
repsertSuperiorSupervisor cid afi uid =
|
|
||||||
whenIsJust (afi ^. _avsFirmEMailSuperior) $ \supemail -> forMM_
|
|
||||||
(altM (guessUserByEmail $ stripCI supemail)
|
|
||||||
(catchAVShandler True True False Nothing $ Just . entityKey <$> ldapLookupAndUpsert supemail)
|
|
||||||
) $ \supid -> do
|
|
||||||
let reasonSuperior = Just $ tshow SupervisorReasonAvsSuperior
|
|
||||||
newSupervisor = UserSupervisor supid uid False cid reasonSuperior
|
|
||||||
deleteWhere [UserSupervisorUser ==. uid, UserSupervisorSupervisor !=. supid, UserSupervisorReason ==. reasonSuperior] -- delete previous superiors, if any
|
|
||||||
-- void $ upsertBy (UniqueUserSupervisor supid uid) newSupervisor [company =. cid, reason =. reasonSuperior] -- always update supervisor reason
|
|
||||||
void $ insertUnique $ UserSupervisor supid uid False cid reasonSuperior -- do not change existing supervisor relationship
|
|
||||||
|
|
||||||
-- TODO: CR3: user upsertCompanySuperior instead of repsertSuperiorSupervisor
|
|
||||||
-- upsert company supervisor from AvsFirmEMailSuperior
|
|
||||||
upsertCompanySuperior :: AvsFirmInfo -> Maybe AvsFirmInfo -> DB (Maybe (CompanyId, UserId))
|
|
||||||
upsertCompanySuperior newAfi mbOldAfi = runMaybeT $ do
|
|
||||||
supemail <- MaybeT . pure $ newAfi ^. _avsFirmEMailSuperior
|
|
||||||
supid <- MaybeT $ altM (guessUserByEmail $ stripCI supemail)
|
|
||||||
(catchAVShandler True True False Nothing $ Just . entityKey <$> ldapLookupAndUpsert supemail)
|
|
||||||
cid <- MaybeT $ getAvsCompanyId newAfi
|
|
||||||
lift $ do
|
|
||||||
void $ runMaybeT $ do -- remove old superior, if any
|
|
||||||
oldAfi <- MaybeT $ pure mbOldAfi
|
|
||||||
oldSeml <- MaybeT $ pure $ oldAfi ^. _avsFirmEMailSuperior
|
|
||||||
oldSup <- MaybeT $ guessUserByEmail $ stripCI oldSeml
|
|
||||||
oldCid <- MaybeT $ getAvsCompanyId oldAfi
|
|
||||||
when (oldCid == cid && oldSup /= supid) $ lift $ do
|
|
||||||
let reasonSuperior = Just $ tshow SupervisorReasonAvsSuperior
|
|
||||||
deleteWhere [UserCompanyCompany ==. cid, UserCompanyUser ==. oldSup] -- remove old supervisor from company
|
|
||||||
-- switch supervison
|
|
||||||
-- updateWhere [UserSupervisorCompany ==. Just cid, UserSupervisorSupervisor ==. oldSup, UserSupervisorReason ==. reasonSuperior] [UserSupervisor =. supid] -- not safe, could violate uniqueness
|
|
||||||
E.update $ \usuper -> do
|
|
||||||
E.set usuper [ UserSupervisorSupervisor E.=. E.val supid ]
|
|
||||||
E.where_ $ usuper E.^. UserSupervisorSupervisor E.==. E.val oldSup
|
|
||||||
E.&&. usuper E.^. UserSupervisorCompany E.==. E.justVal cid
|
|
||||||
E.&&. usuper E.^. UserSupervisorReason E.==. E.val reasonSuperior
|
|
||||||
E.&&. E.notExists (do
|
|
||||||
newSuper <- E.from $ E.table @UserSupervisor
|
|
||||||
E.where_ $ newSuper E.^. UserSupervisorSupervisor E.==. E.val supid
|
|
||||||
E.&&. newSuper E.^. UserSupervisorUser E.==. newSuper E.^. UserSupervisorUser
|
|
||||||
)
|
|
||||||
deleteWhere [UserSupervisorCompany ==. Just cid, UserSupervisorSupervisor ==. oldSup, UserSupervisorReason ==. reasonSuperior] -- remove un-updateable remainders, if any
|
|
||||||
-- upsert new superior company supervisor
|
|
||||||
void $ upsertBy (UniqueUserCompany supid cid)
|
|
||||||
(UserCompany supid cid True False 1 True)
|
|
||||||
[UserCompanySupervisor =. True]
|
|
||||||
return (cid,supid)
|
|
||||||
|
|
||||||
|
|
||||||
getAvsCompanyId :: AvsFirmInfo -> DB (Maybe CompanyId)
|
getAvsCompanyId :: AvsFirmInfo -> DB (Maybe CompanyId)
|
||||||
@ -617,7 +564,7 @@ getAvsCompanyId = fmap (fmap entityKey) . getAvsCompany
|
|||||||
|
|
||||||
-- | Query DB from given AvsFirmInfo. Guarantees that all Uniqueness-Constraints are checked. Highly unlikely that Nothing is returned, since all AvsResponseContact always contains an AvsFirmInfo
|
-- | Query DB from given AvsFirmInfo. Guarantees that all Uniqueness-Constraints are checked. Highly unlikely that Nothing is returned, since all AvsResponseContact always contains an AvsFirmInfo
|
||||||
getAvsCompany :: AvsFirmInfo -> DB (Maybe (Entity Company))
|
getAvsCompany :: AvsFirmInfo -> DB (Maybe (Entity Company))
|
||||||
getAvsCompany afi =
|
getAvsCompany afi =
|
||||||
let compName :: CompanyName
|
let compName :: CompanyName
|
||||||
compName = afi ^. _avsFirmFirm . from _CI
|
compName = afi ^. _avsFirmFirm . from _CI
|
||||||
compShorthand :: CompanyShorthand
|
compShorthand :: CompanyShorthand
|
||||||
@ -625,11 +572,11 @@ getAvsCompany afi =
|
|||||||
compAvsId = afi ^. _avsFirmFirmNo
|
compAvsId = afi ^. _avsFirmFirmNo
|
||||||
in firstJustM $ -- legacy treatment, only use UniqueCompnayAvsId in the future
|
in firstJustM $ -- legacy treatment, only use UniqueCompnayAvsId in the future
|
||||||
guardMonoid (compAvsId > 0)
|
guardMonoid (compAvsId > 0)
|
||||||
[ getBy $ UniqueCompanyAvsId compAvsId
|
[ getBy $ UniqueCompanyAvsId compAvsId
|
||||||
, getEntity $ CompanyKey $ compShorthand <> "-" <> ciShow compAvsId
|
, getEntity $ CompanyKey $ compShorthand <> "-" <> ciShow compAvsId
|
||||||
] <>
|
] <>
|
||||||
[ getByFilter [CompanyName ==. compName]
|
[ getByFilter [CompanyName ==. compName]
|
||||||
, getEntity $ CompanyKey compShorthand
|
, getEntity $ CompanyKey compShorthand
|
||||||
]
|
]
|
||||||
|
|
||||||
-- | insert a company from AVS firm info or update an existing one based on previous values
|
-- | insert a company from AVS firm info or update an existing one based on previous values
|
||||||
@ -637,7 +584,7 @@ upsertAvsCompany :: AvsFirmInfo -> Maybe AvsFirmInfo -> DB (Entity Company)
|
|||||||
upsertAvsCompany newAvsFirmInfo mbOldAvsFirmInfo = do
|
upsertAvsCompany newAvsFirmInfo mbOldAvsFirmInfo = do
|
||||||
mbFirmEnt <- getAvsCompany newAvsFirmInfo -- primarily by AvsId, then Shorthand, then name
|
mbFirmEnt <- getAvsCompany newAvsFirmInfo -- primarily by AvsId, then Shorthand, then name
|
||||||
$logInfoS "AVS" [st|upsertAvsCompany: old #{tshow mbFirmEnt} new #{tshow newAvsFirmInfo}|]
|
$logInfoS "AVS" [st|upsertAvsCompany: old #{tshow mbFirmEnt} new #{tshow newAvsFirmInfo}|]
|
||||||
case (mbFirmEnt, mbOldAvsFirmInfo) of
|
cmpEnt <- case (mbFirmEnt, mbOldAvsFirmInfo) of
|
||||||
(Nothing, _) -> do -- insert new company, neither AvsId nor Shorthand exist in DB
|
(Nothing, _) -> do -- insert new company, neither AvsId nor Shorthand exist in DB
|
||||||
afn <- if 0 < newAvsFirmInfo ^. _avsFirmFirmNo
|
afn <- if 0 < newAvsFirmInfo ^. _avsFirmFirmNo
|
||||||
then return $ newAvsFirmInfo ^. _avsFirmFirmNo
|
then return $ newAvsFirmInfo ^. _avsFirmFirmNo
|
||||||
@ -653,19 +600,19 @@ upsertAvsCompany newAvsFirmInfo mbOldAvsFirmInfo = do
|
|||||||
}
|
}
|
||||||
cmp = foldl' upd dmy $ firmInfo2key : firmInfo2companyNo : firmInfo2company
|
cmp = foldl' upd dmy $ firmInfo2key : firmInfo2companyNo : firmInfo2company
|
||||||
$logInfoS "AVS" $ "Insert new company: " <> tshow cmp
|
$logInfoS "AVS" $ "Insert new company: " <> tshow cmp
|
||||||
newCmp <- insertEntity cmp
|
newCmp <- insertEntity cmp
|
||||||
reportAdminProblem $ AdminProblemNewCompany $ entityKey newCmp
|
reportAdminProblem $ AdminProblemNewCompany $ entityKey newCmp
|
||||||
$logInfoS "AVS" "Insert new company completed."
|
$logInfoS "AVS" "Insert new company completed."
|
||||||
return newCmp
|
return newCmp
|
||||||
|
|
||||||
(Just Entity{entityKey=firmid, entityVal=firm}, oldAvsFirmInfo) -> do -- possibly update existing company, if isJust oldAvsFirmInfo and changed occurred
|
(Just Entity{entityKey=firmid, entityVal=firm}, oldAvsFirmInfo) -> do -- possibly update existing company, if isJust oldAvsFirmInfo and changed occurred
|
||||||
let cmp_ups = mapMaybe (mkUpdate' firm newAvsFirmInfo oldAvsFirmInfo) firmInfo2company
|
let cmp_ups = mapMaybe (mkUpdate' firm newAvsFirmInfo oldAvsFirmInfo) firmInfo2company
|
||||||
key_ups = mkUpdate' firm newAvsFirmInfo oldAvsFirmInfo firmInfo2key
|
key_ups = mkUpdate' firm newAvsFirmInfo oldAvsFirmInfo firmInfo2key
|
||||||
uniq_ups <- mkUpdateCheckUnique' firm newAvsFirmInfo oldAvsFirmInfo firmInfo2companyNo
|
uniq_ups <- mkUpdateCheckUnique' firm newAvsFirmInfo oldAvsFirmInfo firmInfo2companyNo
|
||||||
$logInfoS "AVS" [st|Update company #{companyShorthand firm}: #{tshow (length cmp_ups)}, #{tshow (length key_ups)}, #{tshow (length uniq_ups)} for #{tshow oldAvsFirmInfo}|]
|
$logInfoS "AVS" [st|Update company #{companyShorthand firm}: #{tshow (length cmp_ups)}, #{tshow (length key_ups)}, #{tshow (length uniq_ups)} for #{tshow oldAvsFirmInfo}|]
|
||||||
res_cmp <- updateGetEntity firmid $ mcons uniq_ups cmp_ups
|
res_cmp <- updateGetEntity firmid $ mcons uniq_ups cmp_ups
|
||||||
let cmp_id = res_cmp ^. _entityVal . _companyAvsId
|
let cmp_id = res_cmp ^. _entityVal . _companyAvsId
|
||||||
res_cmp2 <- case key_ups of
|
res_cmp2 <- case key_ups of
|
||||||
Just key_up | cmp_id > 0 -> do
|
Just key_up | cmp_id > 0 -> do
|
||||||
$logInfoS "AVS" $ "Updating CompanyShorthand from " <> ciOriginal (companyShorthand firm) <> " to " <> avsFirmAbbreviation newAvsFirmInfo <> " for AvsNo " <> tshow cmp_id
|
$logInfoS "AVS" $ "Updating CompanyShorthand from " <> ciOriginal (companyShorthand firm) <> " to " <> avsFirmAbbreviation newAvsFirmInfo <> " for AvsNo " <> tshow cmp_id
|
||||||
let uniq_cmp = UniqueCompanyAvsId cmp_id
|
let uniq_cmp = UniqueCompanyAvsId cmp_id
|
||||||
@ -676,22 +623,87 @@ upsertAvsCompany newAvsFirmInfo mbOldAvsFirmInfo = do
|
|||||||
if | key_ok -> updateBy uniq_cmp [key_up] -- this is ok, since we have OnUpdateCascade on all CompanyId entries
|
if | key_ok -> updateBy uniq_cmp [key_up] -- this is ok, since we have OnUpdateCascade on all CompanyId entries
|
||||||
| alt_ok -> updateBy uniq_cmp [CompanyShorthand =. alt_key]
|
| alt_ok -> updateBy uniq_cmp [CompanyShorthand =. alt_key]
|
||||||
| otherwise -> $logInfoS "AVS" $ "Update company shorthand failed for " <> ciOriginal cmp_key <> " and " <> ciOriginal alt_key
|
| otherwise -> $logInfoS "AVS" $ "Update company shorthand failed for " <> ciOriginal cmp_key <> " and " <> ciOriginal alt_key
|
||||||
maybeM (return res_cmp) return $ getBy uniq_cmp
|
maybeM (return res_cmp) return $ getBy uniq_cmp
|
||||||
_otherwise -> return res_cmp
|
_otherwise -> return res_cmp
|
||||||
$logInfoS "AVS" "Update company completed."
|
$logInfoS "AVS" "Update company completed."
|
||||||
return res_cmp2
|
return res_cmp2
|
||||||
|
void $ upsertCompanySuperior (Just $ entityKey cmpEnt, newAvsFirmInfo) mbOldAvsFirmInfo -- ensure firmInfo superior is supervisor
|
||||||
|
return cmpEnt
|
||||||
where
|
where
|
||||||
firmInfo2key =
|
firmInfo2key =
|
||||||
CheckUpdate CompanyShorthand $ _avsFirmAbbreviation . from _CI -- Updating primary key works in principle thanks to OnUpdateCascade, but fails due to update get
|
CheckUpdate CompanyShorthand $ _avsFirmAbbreviation . from _CI -- Updating primary key works in principle thanks to OnUpdateCascade, but fails due to update get
|
||||||
firmInfo2companyNo =
|
firmInfo2companyNo =
|
||||||
CheckUpdate CompanyAvsId _avsFirmFirmNo -- Updating a unique needs special considerations; AVS does not update FirmNo, but for legacy reasons we might have companies without a number
|
CheckUpdate CompanyAvsId _avsFirmFirmNo -- Updating a unique needs special considerations; AVS does not update FirmNo, but for legacy reasons we might have companies without a number
|
||||||
firmInfo2company =
|
firmInfo2company =
|
||||||
[ CheckUpdate CompanyName $ _avsFirmFirm . from _CI
|
[ CheckUpdate CompanyName $ _avsFirmFirm . from _CI
|
||||||
, CheckUpdate CompanyPostAddress _avsFirmPostAddress
|
, CheckUpdate CompanyPostAddress _avsFirmPostAddress
|
||||||
, CheckUpdate CompanyEmail $ _avsFirmPrimaryEmail . _Just . from _CI . re _Just
|
, CheckUpdate CompanyEmail $ _avsFirmPrimaryEmail . _Just . from _CI . re _Just
|
||||||
-- , CheckUpdate CompanyPrefersPostal _avsFirmPrefersPostal -- Guessing here is not useful, since postal preference is ignored anyway when there is only one option available
|
-- , CheckUpdate CompanyPrefersPostal _avsFirmPrefersPostal -- Guessing here is not useful, since postal preference is ignored anyway when there is only one option available
|
||||||
]
|
]
|
||||||
|
|
||||||
|
-- upsert company supervisor from AvsFirmEMailSuperior
|
||||||
|
upsertCompanySuperior :: (Maybe CompanyId, AvsFirmInfo) -> Maybe AvsFirmInfo -> DB (Maybe (CompanyId, UserId))
|
||||||
|
upsertCompanySuperior (mbCid, newAfi) mbOldAfi = runMaybeT $ do
|
||||||
|
supemail <- MaybeT . pure $ newAfi ^. _avsFirmEMailSuperior
|
||||||
|
cid <- MaybeT $ altM (pure mbCid) (getAvsCompanyId newAfi)
|
||||||
|
supid <- MaybeT $ altM (guessUserByEmail $ stripCI supemail)
|
||||||
|
(catchAVShandler True True False Nothing $ Just . entityKey <$> ldapLookupAndUpsert supemail)
|
||||||
|
lift $ do
|
||||||
|
let reasonSuperior = Just $ tshow SupervisorReasonAvsSuperior
|
||||||
|
oldChanges <- runMaybeT $ do -- remove old superior, if any
|
||||||
|
oldAfi <- MaybeT $ pure mbOldAfi
|
||||||
|
oldEml <- MaybeT $ pure $ oldAfi ^. _avsFirmEMailSuperior
|
||||||
|
oldCid <- MaybeT $ getAvsCompanyId oldAfi
|
||||||
|
oldSup <- MaybeT $ guessUserByEmail $ stripCI oldEml
|
||||||
|
let supChange = oldSup /= supid
|
||||||
|
when (supChange && oldCid == cid) $ lift $ do
|
||||||
|
-- deleteWhere [UserCompanyCompany ==. cid, UserCompanyUser ==. oldSup] -- remove old supervisor from company NOTE: we leave this to the oldSuperior's AVS update
|
||||||
|
-- switch supervison
|
||||||
|
-- updateWhere [UserSupervisorCompany ==. Just cid, UserSupervisorSupervisor ==. oldSup, UserSupervisorReason ==. reasonSuperior] [UserSupervisor =. supid] -- not safe, could violate uniqueness
|
||||||
|
E.update $ \usuper -> do
|
||||||
|
E.set usuper [ UserSupervisorSupervisor E.=. E.val supid ]
|
||||||
|
E.where_ $ usuper E.^. UserSupervisorSupervisor E.==. E.val oldSup
|
||||||
|
E.&&. usuper E.^. UserSupervisorCompany E.==. E.justVal cid
|
||||||
|
E.&&. usuper E.^. UserSupervisorReason E.==. E.val reasonSuperior
|
||||||
|
E.&&. E.notExists (do
|
||||||
|
newSuper <- E.from $ E.table @UserSupervisor
|
||||||
|
E.where_ $ newSuper E.^. UserSupervisorSupervisor E.==. E.val supid
|
||||||
|
E.&&. newSuper E.^. UserSupervisorUser E.==. newSuper E.^. UserSupervisorUser
|
||||||
|
)
|
||||||
|
deleteWhere [UserSupervisorSupervisor ==. oldSup, UserSupervisorCompany ==. Just cid, UserSupervisorReason ==. reasonSuperior] -- remove un-updateable remainders, if any
|
||||||
|
return (supChange, oldSup)
|
||||||
|
let supChange = fst <$> oldChanges
|
||||||
|
oldSup = snd <$> oldChanges
|
||||||
|
unless (supChange == Just False) $ do
|
||||||
|
-- upsert new superior company supervisor
|
||||||
|
suprEnt <- upsertBy (UniqueUserCompany supid cid)
|
||||||
|
(UserCompany supid cid True False 1 True)
|
||||||
|
[UserCompanySupervisor =. True]
|
||||||
|
E.insertSelectWithConflict UniqueUserSupervisor
|
||||||
|
(do
|
||||||
|
usr <- E.from $ E.table @UserCompany
|
||||||
|
E.where_ $ usr E.^. UserCompanyCompany E.==. E.val cid
|
||||||
|
-- E.&&. E.notExists (do -- restrict to primary company only
|
||||||
|
-- othr <- E.from $ E.table @UserCompany
|
||||||
|
-- E.where_ $ othr E.^. UserCompanyPriority E.>. usr E.^. UserCompanyPriority
|
||||||
|
-- E.&&. othr E.^. UserCompanyUser E.==. usr E.^. UserCompanyUser
|
||||||
|
-- E.&&. othr E.^. UserCompanyCompany E.!=. E.val cid -- redundant due to > above, but likely performance improving
|
||||||
|
-- )
|
||||||
|
return $ UserSupervisor
|
||||||
|
E.<# E.val supid
|
||||||
|
E.<&> (usr E.^. UserCompanyUser)
|
||||||
|
E.<&> E.val (suprEnt ^. _entityVal . _userCompanySupervisorReroute)
|
||||||
|
E.<&> E.justVal cid
|
||||||
|
E.<&> E.val reasonSuperior
|
||||||
|
)
|
||||||
|
(\old new ->
|
||||||
|
[ UserSupervisorCompany E.=. E.coalesce [old E.^. UserSupervisorCompany, new E.^. UserSupervisorCompany]
|
||||||
|
, UserSupervisorReason E.=. E.coalesce [old E.^. UserSupervisorReason , new E.^. UserSupervisorReason ]
|
||||||
|
]
|
||||||
|
)
|
||||||
|
reportAdminProblem $ AdminProblemCompanySuperiorChange supid cid oldSup
|
||||||
|
return (cid,supid)
|
||||||
|
|
||||||
|
|
||||||
queueAvsUpdateByUID :: (MonoFoldable mono, UserId ~ Element mono) => mono -> Maybe Day -> DB Int64
|
queueAvsUpdateByUID :: (MonoFoldable mono, UserId ~ Element mono) => mono -> Maybe Day -> DB Int64
|
||||||
queueAvsUpdateByUID uids = queueAvsUpdateAux (E.table @User) (E.^. UserId) (\usr -> usr E.^. UserId `E.in_` E.vals uids)
|
queueAvsUpdateByUID uids = queueAvsUpdateAux (E.table @User) (E.^. UserId) (\usr -> usr E.^. UserId `E.in_` E.vals uids)
|
||||||
@ -701,14 +713,14 @@ queueAvsUpdateByAID aids = queueAvsUpdateAux (E.table @UserAvs) (E.^. UserAvsUse
|
|||||||
|
|
||||||
-- queueAvsUpdateAux :: E.From (E.SqlExpr (Entity ent)) -> (E.SqlExpr (Entity ent) -> E.SqlExpr (E.Value UserId)) -> (E.SqlExpr (Entity ent) -> E.SqlExpr (E.Value Bool)) -> Maybe Day -> DB Int64
|
-- queueAvsUpdateAux :: E.From (E.SqlExpr (Entity ent)) -> (E.SqlExpr (Entity ent) -> E.SqlExpr (E.Value UserId)) -> (E.SqlExpr (Entity ent) -> E.SqlExpr (E.Value Bool)) -> Maybe Day -> DB Int64
|
||||||
queueAvsUpdateAux :: E.From t -> (t -> E.SqlExpr (E.Value UserId)) -> (t -> E.SqlExpr (E.Value Bool)) -> Maybe Day -> DB Int64
|
queueAvsUpdateAux :: E.From t -> (t -> E.SqlExpr (E.Value UserId)) -> (t -> E.SqlExpr (E.Value Bool)) -> Maybe Day -> DB Int64
|
||||||
queueAvsUpdateAux tbl prj fltr pause = do
|
queueAvsUpdateAux tbl prj fltr pause = do
|
||||||
now <- liftIO getCurrentTime
|
now <- liftIO getCurrentTime
|
||||||
n <- E.insertSelectWithConflictCount UniqueAvsSyncUser
|
n <- E.insertSelectWithConflictCount UniqueAvsSyncUser
|
||||||
( do
|
( do
|
||||||
usr <- E.from tbl
|
usr <- E.from tbl
|
||||||
E.where_ $ fltr usr
|
E.where_ $ fltr usr
|
||||||
return (AvsSync E.<# prj usr E.<&> E.val now E.<&> E.val pause)
|
return (AvsSync E.<# prj usr E.<&> E.val now E.<&> E.val pause)
|
||||||
) (\current excluded ->
|
) (\current excluded ->
|
||||||
[ AvsSyncCreationTime E.=. E.least (current E.^. AvsSyncCreationTime) (excluded E.^. AvsSyncCreationTime)
|
[ AvsSyncCreationTime E.=. E.least (current E.^. AvsSyncCreationTime) (excluded E.^. AvsSyncCreationTime)
|
||||||
, AvsSyncPause E.=. E.greatest (current E.^. AvsSyncPause) (excluded E.^. AvsSyncPause)
|
, AvsSyncPause E.=. E.greatest (current E.^. AvsSyncPause) (excluded E.^. AvsSyncPause)
|
||||||
]
|
]
|
||||||
@ -717,24 +729,24 @@ queueAvsUpdateAux tbl prj fltr pause = do
|
|||||||
return n
|
return n
|
||||||
|
|
||||||
|
|
||||||
-- | Find or upsert User by AvsCardId (with dot), Fraport PersonalNumber, Fraport Email-Address or by prefixed AvsId or prefixed AvsNo;
|
-- | Find or upsert User by AvsCardId (with dot), Fraport PersonalNumber, Fraport Email-Address or by prefixed AvsId or prefixed AvsNo;
|
||||||
-- fail-safe, may or may not update existing users, may insert new users
|
-- fail-safe, may or may not update existing users, may insert new users
|
||||||
-- If an existing User with internal number is found, an AVS update query is executed
|
-- If an existing User with internal number is found, an AVS update query is executed
|
||||||
guessAvsUser :: Text -> Handler (Maybe UserId)
|
guessAvsUser :: Text -> Handler (Maybe UserId)
|
||||||
guessAvsUser (Text.splitAt 6 -> (Text.toUpper -> prefix, readMay -> Just nr))
|
guessAvsUser (Text.splitAt 6 -> (Text.toUpper -> prefix, readMay -> Just nr))
|
||||||
| prefix=="AVSID:" =
|
| prefix=="AVSID:" =
|
||||||
let avsid = AvsPersonId nr in
|
let avsid = AvsPersonId nr in
|
||||||
runDB (getBy $ UniqueUserAvsId avsid) >>= \case
|
runDB (getBy $ UniqueUserAvsId avsid) >>= \case
|
||||||
(Just Entity{entityVal=UserAvs{userAvsUser=uid}}) -> return $ Just uid
|
(Just Entity{entityVal=UserAvs{userAvsUser=uid}}) -> return $ Just uid
|
||||||
Nothing -> catchAVS2message $ Just <$> upsertAvsUserById avsid
|
Nothing -> catchAVS2message $ Just <$> upsertAvsUserById avsid
|
||||||
| prefix=="AVSNO:" =
|
| prefix=="AVSNO:" =
|
||||||
runDB (view (_entityVal . _userAvsUser) <<$>> getByFilter [UserAvsNoPerson ==. nr])
|
runDB (view (_entityVal . _userAvsUser) <<$>> getByFilter [UserAvsNoPerson ==. nr])
|
||||||
guessAvsUser someid@(discernAvsCardPersonalNo -> Just someavsid) =
|
guessAvsUser someid@(discernAvsCardPersonalNo -> Just someavsid) =
|
||||||
catchAVS2message $ upsertAvsUserByCard someavsid >>= \case
|
catchAVS2message $ upsertAvsUserByCard someavsid >>= \case
|
||||||
Nothing | Left{} <- someavsid -> -- attempt to find PersonalNumber in DB
|
Nothing | Left{} <- someavsid -> -- attempt to find PersonalNumber in DB
|
||||||
runDB (getKeyByFilter [UserCompanyPersonalNumber ==. Just someid])
|
runDB (getKeyByFilter [UserCompanyPersonalNumber ==. Just someid])
|
||||||
other -> return other
|
other -> return other
|
||||||
guessAvsUser someid = do
|
guessAvsUser someid = do
|
||||||
try (runDB $ ldapLookupAndUpsert someid) >>= \case
|
try (runDB $ ldapLookupAndUpsert someid) >>= \case
|
||||||
Right Entity{entityKey=uid, entityVal=User{userCompanyPersonalNumber=Just persNo}} -> do -- ensure internal user is linked to avs, if possible
|
Right Entity{entityKey=uid, entityVal=User{userCompanyPersonalNumber=Just persNo}} -> do -- ensure internal user is linked to avs, if possible
|
||||||
let ldapUid = Just uid
|
let ldapUid = Just uid
|
||||||
@ -743,8 +755,8 @@ guessAvsUser someid = do
|
|||||||
return ldapUid
|
return ldapUid
|
||||||
Right Entity{entityKey=uid} -> return $ Just uid
|
Right Entity{entityKey=uid} -> return $ Just uid
|
||||||
other -> do -- attempt to recover by trying other ids
|
other -> do -- attempt to recover by trying other ids
|
||||||
whenIsLeft other (\(err::SomeException) -> $logInfoS "AVS" $ "upsertAvsUser LDAP error " <> tshow err) -- this line primarily forces exception type to catch-all
|
whenIsLeft other (\(err::SomeException) -> $logInfoS "AVS" $ "upsertAvsUser LDAP error " <> tshow err) -- this line primarily forces exception type to catch-all
|
||||||
runDB . runMaybeT $
|
runDB . runMaybeT $
|
||||||
MaybeT (guessUserByEmail $ stripCI someid) -- recall that monadic actions are only executed until first success here
|
MaybeT (guessUserByEmail $ stripCI someid) -- recall that monadic actions are only executed until first success here
|
||||||
<|> MaybeT (getKeyByFilter [UserDisplayName ==. someid])
|
<|> MaybeT (getKeyByFilter [UserDisplayName ==. someid])
|
||||||
|
|
||||||
@ -756,8 +768,8 @@ upsertAvsUserByCard persNo = do
|
|||||||
let qry = case persNo of
|
let qry = case persNo of
|
||||||
Left fpn
|
Left fpn
|
||||||
-> def{ avsPersonQueryInternalPersonalNo = Just fpn } -- recall: default has all fields set to nothing
|
-> def{ avsPersonQueryInternalPersonalNo = Just fpn } -- recall: default has all fields set to nothing
|
||||||
Right AvsFullCardNo{..}
|
Right AvsFullCardNo{..}
|
||||||
-> def{ avsPersonQueryCardNo = Just avsFullCardNo, avsPersonQueryVersionNo = Just avsFullCardVersion }
|
-> def{ avsPersonQueryCardNo = Just avsFullCardNo, avsPersonQueryVersionNo = Just avsFullCardVersion }
|
||||||
-- NOTE: card validity might be outdated, so we must always check diretcly with avs and not within our DB!
|
-- NOTE: card validity might be outdated, so we must always check diretcly with avs and not within our DB!
|
||||||
AvsResponsePerson adps <- avsQuery qry
|
AvsResponsePerson adps <- avsQuery qry
|
||||||
case Set.elems adps of
|
case Set.elems adps of
|
||||||
@ -780,11 +792,11 @@ setLicence :: (PersistUniqueRead backend, MonadThrow m,
|
|||||||
MonadHandler m, HandlerSite m ~ UniWorX,
|
MonadHandler m, HandlerSite m ~ UniWorX,
|
||||||
BaseBackend backend ~ SqlBackend) =>
|
BaseBackend backend ~ SqlBackend) =>
|
||||||
UserId -> AvsLicence -> ReaderT backend m Bool
|
UserId -> AvsLicence -> ReaderT backend m Bool
|
||||||
setLicence uid lic =
|
setLicence uid lic =
|
||||||
getBy (UniqueUserAvsUser uid) >>= \case
|
getBy (UniqueUserAvsUser uid) >>= \case
|
||||||
Just Entity{entityVal=UserAvs{userAvsPersonId=api}} -> setLicenceAvs api lic
|
Just Entity{entityVal=UserAvs{userAvsPersonId=api}} -> setLicenceAvs api lic
|
||||||
Nothing -> do
|
Nothing -> do
|
||||||
uname <- userDisplayName <<$>> get uid
|
uname <- userDisplayName <<$>> get uid
|
||||||
throwM $ AvsUserUnassociated $ fromMaybe "user id unknown" uname
|
throwM $ AvsUserUnassociated $ fromMaybe "user id unknown" uname
|
||||||
|
|
||||||
setLicenceAvs :: (MonadHandler m, MonadThrow m, HandlerSite m ~ UniWorX) =>
|
setLicenceAvs :: (MonadHandler m, MonadThrow m, HandlerSite m ~ UniWorX) =>
|
||||||
@ -797,7 +809,7 @@ setLicenceAvs apid lic = do
|
|||||||
--setLicencesAvs :: Set AvsPersonLicence -> Handler Bool
|
--setLicencesAvs :: Set AvsPersonLicence -> Handler Bool
|
||||||
setLicencesAvs :: (MonadHandler m, MonadThrow m, HandlerSite m ~ UniWorX) =>
|
setLicencesAvs :: (MonadHandler m, MonadThrow m, HandlerSite m ~ UniWorX) =>
|
||||||
Set AvsPersonLicence -> m Int
|
Set AvsPersonLicence -> m Int
|
||||||
setLicencesAvs = aux 0
|
setLicencesAvs = aux 0
|
||||||
where
|
where
|
||||||
aux batch0_ok pls
|
aux batch0_ok pls
|
||||||
| Set.null pls = return batch0_ok
|
| Set.null pls = return batch0_ok
|
||||||
@ -816,7 +828,7 @@ setLicencesAvs = aux 0
|
|||||||
bad = Map.withoutKeys (setToMap avsResponsePersonID bad') ok_ids -- it is possible to receive an id multiple times, with only one success, but this is sufficient
|
bad = Map.withoutKeys (setToMap avsResponsePersonID bad') ok_ids -- it is possible to receive an id multiple times, with only one success, but this is sufficient
|
||||||
batch1_ok = Set.size ok
|
batch1_ok = Set.size ok
|
||||||
forM_ bad $ \AvsLicenceResponse { avsResponsePersonID=api, avsResponseMessage=msg} ->
|
forM_ bad $ \AvsLicenceResponse { avsResponsePersonID=api, avsResponseMessage=msg} ->
|
||||||
$logErrorS "AVS" $ "Set AVS Licence failed for " <> tshow api <> " due to " <> cropText msg
|
$logErrorS "AVS" $ "Set AVS Licence failed for " <> tshow api <> " due to " <> cropText msg
|
||||||
aux (batch0_ok + batch1_ok) batch2 -- yay for tail recursion (TODO: maybe refactor?)
|
aux (batch0_ok + batch1_ok) batch2 -- yay for tail recursion (TODO: maybe refactor?)
|
||||||
|
|
||||||
{- NOT USED ANYWHERE:
|
{- NOT USED ANYWHERE:
|
||||||
@ -846,13 +858,13 @@ data AvsLicenceDifferences = AvsLicenceDifferences
|
|||||||
#ifndef DEVELOPMENT
|
#ifndef DEVELOPMENT
|
||||||
-- avsLicenceDifferences2LicenceIds is not used in DEVELOPMENT build
|
-- avsLicenceDifferences2LicenceIds is not used in DEVELOPMENT build
|
||||||
avsLicenceDifferences2LicenceIds :: AvsLicenceDifferences -> Set AvsPersonId
|
avsLicenceDifferences2LicenceIds :: AvsLicenceDifferences -> Set AvsPersonId
|
||||||
avsLicenceDifferences2LicenceIds AvsLicenceDifferences{..} = Set.unions
|
avsLicenceDifferences2LicenceIds AvsLicenceDifferences{..} = Set.unions
|
||||||
[ avsLicenceDiffRevokeAll
|
[ avsLicenceDiffRevokeAll
|
||||||
, avsLicenceDiffGrantVorfeld
|
, avsLicenceDiffGrantVorfeld
|
||||||
, avsLicenceDiffRevokeRollfeld
|
, avsLicenceDiffRevokeRollfeld
|
||||||
, avsLicenceDiffGrantRollfeld
|
, avsLicenceDiffGrantRollfeld
|
||||||
]
|
]
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
avsLicenceDifferences2personLicences :: AvsLicenceDifferences -> Set AvsPersonLicence
|
avsLicenceDifferences2personLicences :: AvsLicenceDifferences -> Set AvsPersonLicence
|
||||||
avsLicenceDifferences2personLicences AvsLicenceDifferences{..} =
|
avsLicenceDifferences2personLicences AvsLicenceDifferences{..} =
|
||||||
@ -876,7 +888,7 @@ retrieveDifferingLicencesStatus :: Handler (AvsLicenceDifferences, AvsPersonIdMa
|
|||||||
retrieveDifferingLicencesStatus = retrieveDifferingLicences' True
|
retrieveDifferingLicencesStatus = retrieveDifferingLicences' True
|
||||||
|
|
||||||
retrieveDifferingLicences' :: Bool -> Handler (AvsLicenceDifferences, AvsPersonIdMapPersonCard)
|
retrieveDifferingLicences' :: Bool -> Handler (AvsLicenceDifferences, AvsPersonIdMapPersonCard)
|
||||||
retrieveDifferingLicences' getStatus = do
|
retrieveDifferingLicences' getStatus = do
|
||||||
#ifdef DEVELOPMENT
|
#ifdef DEVELOPMENT
|
||||||
avsUsrs <- runDB $ selectList [] [LimitTo 444]
|
avsUsrs <- runDB $ selectList [] [LimitTo 444]
|
||||||
let allLicences = AvsResponseGetLicences $ Set.fromList $
|
let allLicences = AvsResponseGetLicences $ Set.fromList $
|
||||||
@ -886,33 +898,33 @@ retrieveDifferingLicences' getStatus = do
|
|||||||
, AvsPersonLicence AvsLicenceVorfeld $ AvsPersonId 2 -- AVS:1 FD:0 (ungültig)
|
, AvsPersonLicence AvsLicenceVorfeld $ AvsPersonId 2 -- AVS:1 FD:0 (ungültig)
|
||||||
-- , AvsPersonLicence AvsLicenceVorfeld $ AvsPersonId 4 -- AVS:1 FD:1
|
-- , AvsPersonLicence AvsLicenceVorfeld $ AvsPersonId 4 -- AVS:1 FD:1
|
||||||
] ++ [AvsPersonLicence AvsLicenceVorfeld avsid | Entity _ UserAvs{userAvsPersonId = avsid} <- avsUsrs]
|
] ++ [AvsPersonLicence AvsLicenceVorfeld avsid | Entity _ UserAvs{userAvsPersonId = avsid} <- avsUsrs]
|
||||||
#else
|
#else
|
||||||
allLicences <- avsQuery AvsQueryGetAllLicences
|
allLicences <- avsQuery AvsQueryGetAllLicences
|
||||||
#endif
|
#endif
|
||||||
lDiff <- getDifferingLicences allLicences
|
lDiff <- getDifferingLicences allLicences
|
||||||
#ifdef DEVELOPMENT
|
#ifdef DEVELOPMENT
|
||||||
let mkAdpc valid color = AvsDataPersonCard valid Nothing Nothing color (Set.singleton 'F') Nothing Nothing Nothing Nothing (AvsCardNo "1234") "5"
|
let mkAdpc valid color = AvsDataPersonCard valid Nothing Nothing color (Set.singleton 'F') Nothing Nothing Nothing Nothing (AvsCardNo "1234") "5"
|
||||||
lStat = AvsResponseStatus $ bool mempty fakes getStatus -- not really needed, but avoids unused variable error
|
lStat = AvsResponseStatus $ bool mempty fakes getStatus -- not really needed, but avoids unused variable error
|
||||||
fakes = Set.fromList $
|
fakes = Set.fromList $
|
||||||
[ AvsStatusPerson (AvsPersonId 77 ) $ Set.singleton $ mkAdpc True AvsCardColorGelb
|
[ AvsStatusPerson (AvsPersonId 77 ) $ Set.singleton $ mkAdpc True AvsCardColorGelb
|
||||||
, AvsStatusPerson (AvsPersonId 12345678) $ Set.fromList [mkAdpc False AvsCardColorGrün, mkAdpc True AvsCardColorGelb, mkAdpc False AvsCardColorBlau, mkAdpc True AvsCardColorRot, mkAdpc True $ AvsCardColorMisc "Violett"]
|
, AvsStatusPerson (AvsPersonId 12345678) $ Set.fromList [mkAdpc False AvsCardColorGrün, mkAdpc True AvsCardColorGelb, mkAdpc False AvsCardColorBlau, mkAdpc True AvsCardColorRot, mkAdpc True $ AvsCardColorMisc "Violett"]
|
||||||
, AvsStatusPerson (AvsPersonId 5 ) $ Set.fromList [mkAdpc True AvsCardColorGrün, mkAdpc False AvsCardColorGelb, mkAdpc True AvsCardColorBlau, mkAdpc False AvsCardColorRot, mkAdpc True $ AvsCardColorMisc "Pink"]
|
, AvsStatusPerson (AvsPersonId 5 ) $ Set.fromList [mkAdpc True AvsCardColorGrün, mkAdpc False AvsCardColorGelb, mkAdpc True AvsCardColorBlau, mkAdpc False AvsCardColorRot, mkAdpc True $ AvsCardColorMisc "Pink"]
|
||||||
, AvsStatusPerson (AvsPersonId 2 ) $ Set.singleton $ mkAdpc True AvsCardColorGrün
|
, AvsStatusPerson (AvsPersonId 2 ) $ Set.singleton $ mkAdpc True AvsCardColorGrün
|
||||||
] <>
|
] <>
|
||||||
[ AvsStatusPerson avsid $ Set.singleton $ mkAdpc (even $ avsPersonId avsid) AvsCardColorGelb | Entity _ UserAvs{userAvsPersonId = avsid} <- avsUsrs ]
|
[ AvsStatusPerson avsid $ Set.singleton $ mkAdpc (even $ avsPersonId avsid) AvsCardColorGelb | Entity _ UserAvs{userAvsPersonId = avsid} <- avsUsrs ]
|
||||||
#else
|
#else
|
||||||
let statQry = avsLicenceDifferences2LicenceIds lDiff
|
let statQry = avsLicenceDifferences2LicenceIds lDiff
|
||||||
lStat <- if getStatus && notNull statQry
|
lStat <- if getStatus && notNull statQry
|
||||||
then avsQueryNoCache (AvsQueryStatus statQry)
|
then avsQueryNoCache (AvsQueryStatus statQry)
|
||||||
-- `catch` handler
|
-- `catch` handler
|
||||||
-- let handler _exception = do
|
-- let handler _exception = do
|
||||||
-- addMessage Error $ toHtml $ "avsQueryStatus failed for " <> tshow (length statQry) <> " requests with: \n" <> tshow err <> "\nREQUEST:\n" <> tshow statQry
|
-- addMessage Error $ toHtml $ "avsQueryStatus failed for " <> tshow (length statQry) <> " requests with: \n" <> tshow err <> "\nREQUEST:\n" <> tshow statQry
|
||||||
-- return $ AvsResponseStatus mempty
|
-- return $ AvsResponseStatus mempty
|
||||||
else return $ AvsResponseStatus mempty -- avoid unnecessary avs calls
|
else return $ AvsResponseStatus mempty -- avoid unnecessary avs calls
|
||||||
#endif
|
#endif
|
||||||
return (lDiff, avsResponseStatusMap lStat)
|
return (lDiff, avsResponseStatusMap lStat)
|
||||||
|
|
||||||
|
|
||||||
getDifferingLicences :: AvsResponseGetLicences -> Handler AvsLicenceDifferences
|
getDifferingLicences :: AvsResponseGetLicences -> Handler AvsLicenceDifferences
|
||||||
getDifferingLicences (AvsResponseGetLicences licences) = do
|
getDifferingLicences (AvsResponseGetLicences licences) = do
|
||||||
now <- liftIO getCurrentTime
|
now <- liftIO getCurrentTime
|
||||||
@ -934,7 +946,7 @@ getDifferingLicences (AvsResponseGetLicences licences) = do
|
|||||||
(quali E.^. QualificationId E.==. qualUser E.^. QualificationUserQualification)
|
(quali E.^. QualificationId E.==. qualUser E.^. QualificationUserQualification)
|
||||||
-- NOTE: filters on the innerJoin must be part of ON-condition in order for anti-join to work!
|
-- NOTE: filters on the innerJoin must be part of ON-condition in order for anti-join to work!
|
||||||
E.&&. (quali E.^. QualificationAvsLicence E.==. E.justVal lic) -- correct type of licence
|
E.&&. (quali E.^. QualificationAvsLicence E.==. E.justVal lic) -- correct type of licence
|
||||||
E.&&. (now `validQualification` qualUser) -- currently valid and not blocked
|
E.&&. (now `validQualification` qualUser) -- currently valid and not blocked
|
||||||
)
|
)
|
||||||
`E.innerJoin` E.table @UserAvs
|
`E.innerJoin` E.table @UserAvs
|
||||||
`E.on` (\(_ :& qualUser :& usrAvs) -> qualUser E.^. QualificationUserUser E.==. usrAvs E.^. UserAvsUser)
|
`E.on` (\(_ :& qualUser :& usrAvs) -> qualUser E.^. QualificationUserUser E.==. usrAvs E.^. UserAvsUser)
|
||||||
@ -953,16 +965,16 @@ getDifferingLicences (AvsResponseGetLicences licences) = do
|
|||||||
((vorfGrant, vorfRevoke), (rollGrant, rollRevoke)) <- runDB $ (,)
|
((vorfGrant, vorfRevoke), (rollGrant, rollRevoke)) <- runDB $ (,)
|
||||||
<$> antijoinAvsLicences AvsLicenceVorfeld vorORrollfeld
|
<$> antijoinAvsLicences AvsLicenceVorfeld vorORrollfeld
|
||||||
<*> antijoinAvsLicences AvsLicenceRollfeld rollfeld
|
<*> antijoinAvsLicences AvsLicenceRollfeld rollfeld
|
||||||
let setTo0 = vorfRevoke -- revoke driving licences
|
let setTo0 = vorfRevoke -- revoke driving licences
|
||||||
setTo1up = vorfGrant Set.\\ rollGrant -- grant apron driving licence
|
setTo1up = vorfGrant Set.\\ rollGrant -- grant apron driving licence
|
||||||
setTo1down = rollRevoke Set.\\ vorfRevoke -- revoke maneuvering area licence, but retain apron driving licence
|
setTo1down = rollRevoke Set.\\ vorfRevoke -- revoke maneuvering area licence, but retain apron driving licence
|
||||||
setTo2 = (rollGrant Set.\\ vorfRevoke) `Set.intersection` (vorfGrant `Set.union` vorORrollfeld) -- grant maneuvering driving licence
|
setTo2 = (rollGrant Set.\\ vorfRevoke) `Set.intersection` (vorfGrant `Set.union` vorORrollfeld) -- grant maneuvering driving licence
|
||||||
return AvsLicenceDifferences
|
return AvsLicenceDifferences
|
||||||
{ avsLicenceDiffRevokeAll = setTo0
|
{ avsLicenceDiffRevokeAll = setTo0
|
||||||
, avsLicenceDiffGrantVorfeld = setTo1up
|
, avsLicenceDiffGrantVorfeld = setTo1up
|
||||||
, avsLicenceDiffRevokeRollfeld = setTo1down
|
, avsLicenceDiffRevokeRollfeld = setTo1down
|
||||||
, avsLicenceDiffGrantRollfeld = setTo2
|
, avsLicenceDiffGrantRollfeld = setTo2
|
||||||
}
|
}
|
||||||
{- Cases to consider (AVS_Licence,has_valid_F, has_valid_R) -> (vorfeld@(toset,unset), rollfeld@(toset,unset)) :
|
{- Cases to consider (AVS_Licence,has_valid_F, has_valid_R) -> (vorfeld@(toset,unset), rollfeld@(toset,unset)) :
|
||||||
A (0,0,0) -> ((_,_),(_,_)) : nop; avs_id not returned from queries, no problem
|
A (0,0,0) -> ((_,_),(_,_)) : nop; avs_id not returned from queries, no problem
|
||||||
B (0,0,1) -> ((_,_),(x,_)) : nop; do nothing -- CHECK since id is returned by roll-query
|
B (0,0,1) -> ((_,_),(x,_)) : nop; do nothing -- CHECK since id is returned by roll-query
|
||||||
|
|||||||
@ -26,14 +26,14 @@ company2msg = text2message . ciOriginal . unCompanyKey
|
|||||||
|
|
||||||
wgtCompanies :: UserId -> DB (Maybe Widget)
|
wgtCompanies :: UserId -> DB (Maybe Widget)
|
||||||
wgtCompanies = \uid -> do
|
wgtCompanies = \uid -> do
|
||||||
companies <- E.select $ do
|
companies <- E.select $ do
|
||||||
(usrComp :& comp) <- E.from $ E.table @UserCompany `E.innerJoin` E.table @Company
|
(usrComp :& comp) <- E.from $ E.table @UserCompany `E.innerJoin` E.table @Company
|
||||||
`E.on` (\(usrComp :& comp) -> usrComp E.^. UserCompanyCompany E.==. comp E.^. CompanyId)
|
`E.on` (\(usrComp :& comp) -> usrComp E.^. UserCompanyCompany E.==. comp E.^. CompanyId)
|
||||||
E.where_ $ usrComp E.^. UserCompanyUser E.==. E.val uid
|
E.where_ $ usrComp E.^. UserCompanyUser E.==. E.val uid
|
||||||
E.orderBy [E.asc (comp E.^. CompanyName)]
|
E.orderBy [E.asc (comp E.^. CompanyName)]
|
||||||
return (comp E.^. CompanyShorthand, comp E.^. CompanyName, usrComp E.^. UserCompanySupervisor, usrComp E.^. UserCompanyPriority)
|
return (comp E.^. CompanyShorthand, comp E.^. CompanyName, usrComp E.^. UserCompanySupervisor, usrComp E.^. UserCompanyPriority)
|
||||||
let (mPri, topCmp, otherCmp) = procCmp mPri companies
|
let (mPri, topCmp, otherCmp) = procCmp mPri companies
|
||||||
resWgt =
|
resWgt =
|
||||||
[whamlet|
|
[whamlet|
|
||||||
$forall c <- topCmp
|
$forall c <- topCmp
|
||||||
<p>
|
<p>
|
||||||
@ -43,7 +43,7 @@ wgtCompanies = \uid -> do
|
|||||||
#{c}
|
#{c}
|
||||||
|]
|
|]
|
||||||
return $ toMaybe (notNull topCmp) resWgt
|
return $ toMaybe (notNull topCmp) resWgt
|
||||||
where
|
where
|
||||||
procCmp _ [] = (0, [],[])
|
procCmp _ [] = (0, [],[])
|
||||||
procCmp maxPri ((E.Value cmpSh, E.Value cmpName, E.Value cmpSpr, E.Value cmpPrio) : cs) =
|
procCmp maxPri ((E.Value cmpSh, E.Value cmpName, E.Value cmpSpr, E.Value cmpPrio) : cs) =
|
||||||
let cmpWgt = companyWidget (cmpSh, cmpName, cmpSpr)
|
let cmpWgt = companyWidget (cmpSh, cmpName, cmpSpr)
|
||||||
@ -53,15 +53,22 @@ wgtCompanies = \uid -> do
|
|||||||
|
|
||||||
-- TODO: use this function in company view Handler.Firm #157
|
-- TODO: use this function in company view Handler.Firm #157
|
||||||
-- | add all company supervisors for a given users
|
-- | add all company supervisors for a given users
|
||||||
addCompanySupervisors :: (MonadIO m, BackendCompatible SqlBackend backend, PersistQueryWrite backend, PersistUniqueWrite backend)
|
addCompanySupervisors :: (MonadIO m, BackendCompatible SqlBackend backend, PersistQueryWrite backend, PersistUniqueWrite backend)
|
||||||
=> Key Company -> Key User -> ReaderT backend m ()
|
=> Key Company -> Key User -> ReaderT backend m ()
|
||||||
addCompanySupervisors cid uid =
|
addCompanySupervisors cid uid =
|
||||||
E.insertSelectWithConflict
|
E.insertSelectWithConflict
|
||||||
UniqueUserSupervisor
|
UniqueUserSupervisor
|
||||||
( do
|
( do
|
||||||
userCompany <- E.from $ E.table @UserCompany
|
userCompany <- E.from $ E.table @UserCompany
|
||||||
E.where_ $ userCompany E.^. UserCompanyCompany E.==. E.val cid
|
E.where_ $ userCompany E.^. UserCompanyCompany E.==. E.val cid
|
||||||
E.&&. userCompany E.^. UserCompanySupervisor
|
E.&&. userCompany E.^. UserCompanySupervisor
|
||||||
|
-- E.&&. E.notExists (do -- restrict to primary company only
|
||||||
|
-- othr <- E.from $ E.table @UserCompany
|
||||||
|
-- E.where_ $ othr E.^. UserCompanyPriority E.>. userCompany E.^. UserCompanyPriority
|
||||||
|
-- E.&&. othr E.^. UserCompanyUser E.==. userCompany E.^. UserCompanyUser
|
||||||
|
-- E.&&. othr E.^. UserCompanyCompany E.!=. E.val cid -- redundant due to > above, but likely performance improving
|
||||||
|
-- )
|
||||||
|
|
||||||
return $ UserSupervisor
|
return $ UserSupervisor
|
||||||
E.<# (userCompany E.^. UserCompanyUser)
|
E.<# (userCompany E.^. UserCompanyUser)
|
||||||
E.<&> E.val uid
|
E.<&> E.val uid
|
||||||
@ -72,7 +79,7 @@ addCompanySupervisors cid uid =
|
|||||||
(\current excluded -> -- Supervision between chosen individuals exists already; keep old reason and company, if exists
|
(\current excluded -> -- Supervision between chosen individuals exists already; keep old reason and company, if exists
|
||||||
[ UserSupervisorCompany E.=. E.coalesce [current E.^. UserSupervisorCompany, excluded E.^. UserSupervisorCompany] -- do we want this? Ok, since we delete unconditionally first?!
|
[ UserSupervisorCompany E.=. E.coalesce [current E.^. UserSupervisorCompany, excluded E.^. UserSupervisorCompany] -- do we want this? Ok, since we delete unconditionally first?!
|
||||||
, UserSupervisorReason E.=. E.coalesce [current E.^. UserSupervisorReason , excluded E.^. UserSupervisorReason ]
|
, UserSupervisorReason E.=. E.coalesce [current E.^. UserSupervisorReason , excluded E.^. UserSupervisorReason ]
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@ -80,7 +87,7 @@ addCompanySupervisors cid uid =
|
|||||||
switchAvsUserCompany :: Bool -> Bool -> UserId -> CompanyId -> DB ([Update User], [AdminProblem])
|
switchAvsUserCompany :: Bool -> Bool -> UserId -> CompanyId -> DB ([Update User], [AdminProblem])
|
||||||
switchAvsUserCompany usrPostEmailUpds keepOldCompanySupervs uid newCompanyId = do
|
switchAvsUserCompany usrPostEmailUpds keepOldCompanySupervs uid newCompanyId = do
|
||||||
usrRec <- get404 uid
|
usrRec <- get404 uid
|
||||||
newCompany <- get404 newCompanyId
|
newCompany <- get404 newCompanyId
|
||||||
mbUsrComp <- getUserPrimaryCompany uid
|
mbUsrComp <- getUserPrimaryCompany uid
|
||||||
mbOldComp <- (get . userCompanyCompany) `traverseJoin` mbUsrComp
|
mbOldComp <- (get . userCompanyCompany) `traverseJoin` mbUsrComp
|
||||||
mbUsrAvs <- if usrPostEmailUpds then getBy (UniqueUserAvsUser uid) else return Nothing
|
mbUsrAvs <- if usrPostEmailUpds then getBy (UniqueUserAvsUser uid) else return Nothing
|
||||||
@ -89,14 +96,14 @@ switchAvsUserCompany usrPostEmailUpds keepOldCompanySupervs uid newCompanyId = d
|
|||||||
usrPostUp = toMaybe (usrPostEmailUpds && fromMaybe False (liftA2 isSimilarMarkup usrPostAddr avsPostAddr))
|
usrPostUp = toMaybe (usrPostEmailUpds && fromMaybe False (liftA2 isSimilarMarkup usrPostAddr avsPostAddr))
|
||||||
(UserPostAddress =. Nothing) -- use company address indirectly instead
|
(UserPostAddress =. Nothing) -- use company address indirectly instead
|
||||||
usrPrefPost = userPrefersPostal usrRec
|
usrPrefPost = userPrefersPostal usrRec
|
||||||
usrPrefPostUp = toMaybe (Just usrPrefPost == (mbOldComp ^? _Just . _companyPrefersPostal))
|
usrPrefPostUp = toMaybe (Just usrPrefPost == (mbOldComp ^? _Just . _companyPrefersPostal))
|
||||||
(UserPrefersPostal =. companyPrefersPostal newCompany)
|
(UserPrefersPostal =. companyPrefersPostal newCompany)
|
||||||
usrEmail :: UserEmail = userDisplayEmail usrRec
|
usrEmail :: UserEmail = userDisplayEmail usrRec
|
||||||
avsEmail :: Maybe UserEmail = mbUsrAvs ^? _Just . _entityVal . _userAvsLastFirmInfo . _Just . _avsFirmPrimaryEmail . _Just . from _CI
|
avsEmail :: Maybe UserEmail = mbUsrAvs ^? _Just . _entityVal . _userAvsLastFirmInfo . _Just . _avsFirmPrimaryEmail . _Just . from _CI
|
||||||
usrEmailUp = toMaybe (usrPostEmailUpds && avsEmail == Just usrEmail) (UserDisplayEmail =. "")
|
usrEmailUp = toMaybe (usrPostEmailUpds && avsEmail == Just usrEmail) (UserDisplayEmail =. "")
|
||||||
usrUpdate = catMaybes [usrPostUp, usrPrefPostUp, usrEmailUp]
|
usrUpdate = catMaybes [usrPostUp, usrPrefPostUp, usrEmailUp]
|
||||||
-- [UserPostAddress =. Nothing, UserPrefersPostal =. companyPrefersPostal newCompany] -- unconditional
|
-- [UserPostAddress =. Nothing, UserPrefersPostal =. companyPrefersPostal newCompany] -- unconditional
|
||||||
-- update uid usrUpdate
|
-- update uid usrUpdate
|
||||||
-- repsertSuperiorSupervisor is not called here, since the Superior is indepentent of the actual company association
|
-- repsertSuperiorSupervisor is not called here, since the Superior is indepentent of the actual company association
|
||||||
case mbUsrComp of
|
case mbUsrComp of
|
||||||
Nothing -> do -- create company user
|
Nothing -> do -- create company user
|
||||||
@ -105,10 +112,10 @@ switchAvsUserCompany usrPostEmailUpds keepOldCompanySupervs uid newCompanyId = d
|
|||||||
return (usrUpdate, mempty)
|
return (usrUpdate, mempty)
|
||||||
Just UserCompany{userCompanyCompany=oldCompanyId, userCompanyPriority=oldPrio, userCompanySupervisor=oldSuper, userCompanySupervisorReroute=oldSuperReroute}
|
Just UserCompany{userCompanyCompany=oldCompanyId, userCompanyPriority=oldPrio, userCompanySupervisor=oldSuper, userCompanySupervisorReroute=oldSuperReroute}
|
||||||
| newCompanyId == oldCompanyId -> return mempty -- nothing to do
|
| newCompanyId == oldCompanyId -> return mempty -- nothing to do
|
||||||
| otherwise -> do -- switch company
|
| otherwise -> do -- switch company
|
||||||
void $ upsertBy (UniqueUserCompany uid newCompanyId) newUserComp
|
void $ upsertBy (UniqueUserCompany uid newCompanyId) newUserComp
|
||||||
[UserCompanyPriority =. succ oldPrio, UserCompanySupervisor =. False, UserCompanySupervisorReroute =. False, UserCompanyUseCompanyAddress =. True]
|
[UserCompanyPriority =. succ oldPrio, UserCompanySupervisor =. False, UserCompanySupervisorReroute =. False, UserCompanyUseCompanyAddress =. True]
|
||||||
-- supervised by uid
|
-- supervised by uid
|
||||||
supervisees :: [(Entity UserSupervisor, E.Value Bool)] <- E.select $ do
|
supervisees :: [(Entity UserSupervisor, E.Value Bool)] <- E.select $ do
|
||||||
usrSup <- E.from $ E.table @UserSupervisor
|
usrSup <- E.from $ E.table @UserSupervisor
|
||||||
E.where_ $ usrSup E.^. UserSupervisorSupervisor E.==. E.val uid
|
E.where_ $ usrSup E.^. UserSupervisorSupervisor E.==. E.val uid
|
||||||
@ -118,14 +125,14 @@ switchAvsUserCompany usrPostEmailUpds keepOldCompanySupervs uid newCompanyId = d
|
|||||||
othSup <- E.from $ E.table @UserSupervisor
|
othSup <- E.from $ E.table @UserSupervisor
|
||||||
E.where_ $ usrSup E.^. UserSupervisorUser E.==. othSup E.^. UserSupervisorUser
|
E.where_ $ usrSup E.^. UserSupervisorUser E.==. othSup E.^. UserSupervisorUser
|
||||||
E.&&. othSup E.^. UserSupervisorCompany E.~=. E.val oldCompanyId
|
E.&&. othSup E.^. UserSupervisorCompany E.~=. E.val oldCompanyId
|
||||||
E.&&. othSup E.^. UserSupervisorReason E.~=. E.val superReasonComDef
|
E.&&. othSup E.^. UserSupervisorReason E.~=. E.val superReasonComDef
|
||||||
return (usrSup, singleSup)
|
return (usrSup, singleSup)
|
||||||
newlyUnsupervised <- guardMonoidM (notNull supervisees) $ do
|
newlyUnsupervised <- guardMonoidM (notNull supervisees) $ do
|
||||||
E.delete $ do
|
E.delete $ do
|
||||||
usrSup <- E.from $ E.table @UserSupervisor
|
usrSup <- E.from $ E.table @UserSupervisor
|
||||||
E.where_ $ usrSup E.^. UserSupervisorId `E.in_` E.vals (fmap (entityKey . fst) supervisees)
|
E.where_ $ usrSup E.^. UserSupervisorId `E.in_` E.vals (fmap (entityKey . fst) supervisees)
|
||||||
return $ [ AdminProblemSupervisorLeftCompany subid oldCompanyId oldSuperReroute
|
return $ [ AdminProblemSupervisorLeftCompany subid oldCompanyId oldSuperReroute
|
||||||
| (Entity{entityVal=UserSupervisor{userSupervisorUser=subid}}, E.Value True) <- supervisees ]
|
| (Entity{entityVal=UserSupervisor{userSupervisorUser=subid}}, E.Value True) <- supervisees ]
|
||||||
-- supervisors of uid
|
-- supervisors of uid
|
||||||
let superDeftFltr = (UserSupervisorUser ==. uid) : (UserSupervisorReason ~=. superReasonComDef)
|
let superDeftFltr = (UserSupervisorUser ==. uid) : (UserSupervisorReason ~=. superReasonComDef)
|
||||||
oldSubFltr = (UserSupervisorCompany ~=. oldCompanyId) <> superDeftFltr
|
oldSubFltr = (UserSupervisorCompany ~=. oldCompanyId) <> superDeftFltr
|
||||||
@ -139,6 +146,6 @@ switchAvsUserCompany usrPostEmailUpds keepOldCompanySupervs uid newCompanyId = d
|
|||||||
$ bcons isNoLongerSupervised (AdminProblemNewlyUnsupervised uid (Just oldCompanyId) newCompanyId)
|
$ bcons isNoLongerSupervised (AdminProblemNewlyUnsupervised uid (Just oldCompanyId) newCompanyId)
|
||||||
newlyUnsupervised
|
newlyUnsupervised
|
||||||
return (usrUpdate ,problems)
|
return (usrUpdate ,problems)
|
||||||
where
|
where
|
||||||
newUserComp = UserCompany uid newCompanyId False False 1 True -- default value for new company insertion, if no update can be done
|
newUserComp = UserCompany uid newCompanyId False False 1 True -- default value for new company insertion, if no update can be done
|
||||||
superReasonComDef = tshow SupervisorReasonCompanyDefault
|
superReasonComDef = tshow SupervisorReasonCompanyDefault
|
||||||
@ -61,11 +61,18 @@ nameWidget displayName surname = toWidget $ nameHtml displayName surname
|
|||||||
userWidget :: HasUser c => c -> Widget
|
userWidget :: HasUser c => c -> Widget
|
||||||
userWidget x = nameWidget (x ^. _userDisplayName) (x ^._userSurname)
|
userWidget x = nameWidget (x ^. _userDisplayName) (x ^._userSurname)
|
||||||
|
|
||||||
|
userIdWidget :: UserId -> Widget
|
||||||
|
userIdWidget uid = maybeM (msg2widget MsgUserUnknown) userWidget (liftHandler $ runDB $ get uid)
|
||||||
|
|
||||||
linkUserWidget :: HasRoute UniWorX url => (CryptoUUIDUser -> url) -> Entity User -> Widget
|
linkUserWidget :: HasRoute UniWorX url => (CryptoUUIDUser -> url) -> Entity User -> Widget
|
||||||
linkUserWidget lnk (Entity uid usr) = do
|
linkUserWidget lnk (Entity uid usr) = do
|
||||||
uuid <- encrypt uid
|
uuid <- encrypt uid
|
||||||
simpleLink (userWidget usr) (lnk uuid)
|
simpleLink (userWidget usr) (lnk uuid)
|
||||||
|
|
||||||
|
-- | like linkUserWidget, but on Id only. Requires DB access, use with caution
|
||||||
|
linkUserIdWidget :: HasRoute UniWorX url => (CryptoUUIDUser -> url) -> UserId -> Widget
|
||||||
|
linkUserIdWidget lnk uid = maybeM (msg2widget MsgUserUnknown) (linkUserWidget lnk . Entity uid) (liftHandler $ runDB $ get uid)
|
||||||
|
|
||||||
userEmailWidget :: HasUser c => c -> Widget
|
userEmailWidget :: HasUser c => c -> Widget
|
||||||
userEmailWidget x = nameEmailWidget (x ^. _userDisplayEmail) (x ^. _userDisplayName) (x ^. _userSurname)
|
userEmailWidget x = nameEmailWidget (x ^. _userDisplayEmail) (x ^. _userDisplayName) (x ^. _userSurname)
|
||||||
|
|
||||||
@ -139,7 +146,7 @@ companyWidget (csh, cname, isSupervisor) = simpleLink (toWgt name) curl
|
|||||||
where
|
where
|
||||||
curl = FirmUsersR csh
|
curl = FirmUsersR csh
|
||||||
corg = ciOriginal cname
|
corg = ciOriginal cname
|
||||||
name
|
name
|
||||||
| isSupervisor = text2markup (corg <> " ") <> icon IconSupervisor
|
| isSupervisor = text2markup (corg <> " ") <> icon IconSupervisor
|
||||||
| otherwise = text2markup corg
|
| otherwise = text2markup corg
|
||||||
|
|
||||||
@ -260,15 +267,15 @@ roomReferenceWidget RoomReferenceLink{..} = $(widgetFile "widgets/room-reference
|
|||||||
-- Data.Aeson.Encode.Pretty.encodePretty did not render in Html properly, hence jsonWidget
|
-- Data.Aeson.Encode.Pretty.encodePretty did not render in Html properly, hence jsonWidget
|
||||||
jsonWidget :: ToJSON a => a -> Widget
|
jsonWidget :: ToJSON a => a -> Widget
|
||||||
jsonWidget x = jsonWidgetAux $ toJSON x
|
jsonWidget x = jsonWidgetAux $ toJSON x
|
||||||
where
|
where
|
||||||
jsonWidgetAux :: Value -> Widget
|
jsonWidgetAux :: Value -> Widget
|
||||||
jsonWidgetAux Null = [whamlet|Null|]
|
jsonWidgetAux Null = [whamlet|Null|]
|
||||||
jsonWidgetAux (Bool b) = toWidget $ boolSymbol b
|
jsonWidgetAux (Bool b) = toWidget $ boolSymbol b
|
||||||
jsonWidgetAux (String s) = [whamlet|#{s}|]
|
jsonWidgetAux (String s) = [whamlet|#{s}|]
|
||||||
jsonWidgetAux (Number n)
|
jsonWidgetAux (Number n)
|
||||||
| isInteger n = [whamlet|#{formatScientific Fixed (Just 0) n}|]
|
| isInteger n = [whamlet|#{formatScientific Fixed (Just 0) n}|]
|
||||||
| otherwise = [whamlet|#{formatScientific Generic Nothing n}|]
|
| otherwise = [whamlet|#{formatScientific Generic Nothing n}|]
|
||||||
jsonWidgetAux (Array l)
|
jsonWidgetAux (Array l)
|
||||||
| 1 >= length l = foldMap jsonWidgetAux l -- empty arrays don't show
|
| 1 >= length l = foldMap jsonWidgetAux l -- empty arrays don't show
|
||||||
| otherwise =
|
| otherwise =
|
||||||
[whamlet|
|
[whamlet|
|
||||||
@ -285,4 +292,3 @@ jsonWidget x = jsonWidgetAux $ toJSON x
|
|||||||
<dt .deflist__dt>#{k}
|
<dt .deflist__dt>#{k}
|
||||||
<dd .deflist__dd>^{jsonWidgetAux v}
|
<dd .deflist__dd>^{jsonWidgetAux v}
|
||||||
|]
|
|]
|
||||||
|
|
||||||
161
src/Utils.hs
161
src/Utils.hs
@ -11,7 +11,7 @@ import ClassyPrelude.Yesod hiding (foldlM, Proxy, handle, catch, bracket)
|
|||||||
|
|
||||||
-- import Data.Double.Conversion.Text -- faster implementation for textPercent?
|
-- import Data.Double.Conversion.Text -- faster implementation for textPercent?
|
||||||
import qualified Data.Foldable as Fold
|
import qualified Data.Foldable as Fold
|
||||||
import qualified Data.Traversable as Trav
|
import qualified Data.Traversable as Trav
|
||||||
import Data.Foldable as Utils (foldlM, foldrM)
|
import Data.Foldable as Utils (foldlM, foldrM)
|
||||||
import Data.Monoid (First, Sum(..), Endo)
|
import Data.Monoid (First, Sum(..), Endo)
|
||||||
import Data.Proxy
|
import Data.Proxy
|
||||||
@ -265,7 +265,7 @@ addAttrsClass cl attrs = ("class", cl') : noClAttrs
|
|||||||
where
|
where
|
||||||
(clAttrs, noClAttrs) = partition (views _1 $ (== "class") . CI.mk) attrs
|
(clAttrs, noClAttrs) = partition (views _1 $ (== "class") . CI.mk) attrs
|
||||||
cl' = Text.intercalate " " . nubOrd . filter (not . null) $ cl : (views _2 (Text.splitOn " ") =<< clAttrs)
|
cl' = Text.intercalate " " . nubOrd . filter (not . null) $ cl : (views _2 (Text.splitOn " ") =<< clAttrs)
|
||||||
|
|
||||||
---------------------
|
---------------------
|
||||||
-- Text and String --
|
-- Text and String --
|
||||||
---------------------
|
---------------------
|
||||||
@ -289,11 +289,11 @@ stripAll = Text.filter (not . isSpace)
|
|||||||
|
|
||||||
-- | Strips an optional prefix. Like `Data.Text.stripPrefix` but returns input text if the prefix is not matched, micking the behaviour of `dropPrefix` for `Data.Text`
|
-- | Strips an optional prefix. Like `Data.Text.stripPrefix` but returns input text if the prefix is not matched, micking the behaviour of `dropPrefix` for `Data.Text`
|
||||||
dropPrefixText :: Text -> Text -> Text
|
dropPrefixText :: Text -> Text -> Text
|
||||||
-- dropPrefixText p t = fromMaybe t $ stripPrefix p t
|
-- dropPrefixText p t = fromMaybe t $ stripPrefix p t
|
||||||
dropPrefixText p (stripPrefix p -> Just t) = t
|
dropPrefixText p (stripPrefix p -> Just t) = t
|
||||||
dropPrefixText _ other = other
|
dropPrefixText _ other = other
|
||||||
|
|
||||||
-- | take first line, only
|
-- | take first line, only
|
||||||
cropText :: Text -> Text
|
cropText :: Text -> Text
|
||||||
cropText (Text.take 255 -> t) = headDef t $ Text.lines t
|
cropText (Text.take 255 -> t) = headDef t $ Text.lines t
|
||||||
|
|
||||||
@ -302,39 +302,39 @@ tshowCrop = cropText . tshow
|
|||||||
|
|
||||||
-- | strip leading and trailing whitespace and make case insensitive
|
-- | strip leading and trailing whitespace and make case insensitive
|
||||||
-- also helps to avoid the need to import just for CI.mk
|
-- also helps to avoid the need to import just for CI.mk
|
||||||
stripCI :: Text -> CI Text
|
stripCI :: Text -> CI Text
|
||||||
stripCI = CI.mk . Text.strip
|
stripCI = CI.mk . Text.strip
|
||||||
|
|
||||||
-- | Instead of CI.mk, this still allows use of Text.isInfixOf, etc.
|
-- | Instead of CI.mk, this still allows use of Text.isInfixOf, etc.
|
||||||
stripFold :: Text -> Text
|
stripFold :: Text -> Text
|
||||||
stripFold = Text.toCaseFold . Text.strip
|
stripFold = Text.toCaseFold . Text.strip
|
||||||
|
|
||||||
|
|
||||||
-- | just to avoid adding an import for this
|
-- | just to avoid adding an import for this
|
||||||
ciOriginal :: CI Text -> Text
|
ciOriginal :: CI Text -> Text
|
||||||
ciOriginal = CI.original
|
ciOriginal = CI.original
|
||||||
|
|
||||||
ciShow :: Show a => a -> CI Text
|
ciShow :: Show a => a -> CI Text
|
||||||
ciShow = CI.mk . tshow
|
ciShow = CI.mk . tshow
|
||||||
|
|
||||||
citext2lower :: CI Text -> Text
|
citext2lower :: CI Text -> Text
|
||||||
citext2lower = Text.toLower . CI.original
|
citext2lower = Text.toLower . CI.original
|
||||||
|
|
||||||
-- avoids unnecessary imports
|
-- avoids unnecessary imports
|
||||||
citext2string :: CI Text -> String
|
citext2string :: CI Text -> String
|
||||||
citext2string = Text.unpack . CI.original
|
citext2string = Text.unpack . CI.original
|
||||||
|
|
||||||
string2citext :: String -> CI Text
|
string2citext :: String -> CI Text
|
||||||
string2citext = CI.mk . Text.pack
|
string2citext = CI.mk . Text.pack
|
||||||
|
|
||||||
text2AlphaNumPlus :: [Char] -> Text -> Text
|
text2AlphaNumPlus :: [Char] -> Text -> Text
|
||||||
text2AlphaNumPlus =
|
text2AlphaNumPlus =
|
||||||
let alphaNum = Set.fromAscList $ ['0'..'9'] <> ['A'..'Z'] <> ['a'..'z']
|
let alphaNum = Set.fromAscList $ ['0'..'9'] <> ['A'..'Z'] <> ['a'..'z']
|
||||||
in \oks ->
|
in \oks ->
|
||||||
let aNumPlus = Set.fromList oks <> alphaNum
|
let aNumPlus = Set.fromList oks <> alphaNum
|
||||||
in Text.filter (`Set.member` aNumPlus)
|
in Text.filter (`Set.member` aNumPlus)
|
||||||
|
|
||||||
-- | Convert or remove all non-ascii characters, e.g. for filenames
|
-- | Convert or remove all non-ascii characters, e.g. for filenames
|
||||||
text2asciiAlphaNum :: Text -> Text
|
text2asciiAlphaNum :: Text -> Text
|
||||||
text2asciiAlphaNum = text2AlphaNumPlus ['-','_']
|
text2asciiAlphaNum = text2AlphaNumPlus ['-','_']
|
||||||
. Text.replace "ä" "ae"
|
. Text.replace "ä" "ae"
|
||||||
@ -348,9 +348,9 @@ text2asciiAlphaNum = text2AlphaNumPlus ['-','_']
|
|||||||
. Text.replace "á" "a"
|
. Text.replace "á" "a"
|
||||||
. Text.replace "Ö" "Oe"
|
. Text.replace "Ö" "Oe"
|
||||||
. Text.replace "ö" "oe"
|
. Text.replace "ö" "oe"
|
||||||
. Text.replace "œ" "oe"
|
. Text.replace "œ" "oe"
|
||||||
. Text.replace "Ø" "Oe"
|
. Text.replace "Ø" "Oe"
|
||||||
. Text.replace "ø" "oe"
|
. Text.replace "ø" "oe"
|
||||||
. Text.replace "ò" "o"
|
. Text.replace "ò" "o"
|
||||||
. Text.replace "ò" "o"
|
. Text.replace "ò" "o"
|
||||||
. Text.replace "ò" "o"
|
. Text.replace "ò" "o"
|
||||||
@ -359,7 +359,7 @@ text2asciiAlphaNum = text2AlphaNumPlus ['-','_']
|
|||||||
. Text.replace "ü" "ue"
|
. Text.replace "ü" "ue"
|
||||||
. Text.replace "ù" "u"
|
. Text.replace "ù" "u"
|
||||||
. Text.replace "ú" "u"
|
. Text.replace "ú" "u"
|
||||||
. Text.replace "û" "u"
|
. Text.replace "û" "u"
|
||||||
. Text.replace "ë" "e"
|
. Text.replace "ë" "e"
|
||||||
. Text.replace "ê" "e"
|
. Text.replace "ê" "e"
|
||||||
. Text.replace "è" "e"
|
. Text.replace "è" "e"
|
||||||
@ -368,7 +368,7 @@ text2asciiAlphaNum = text2AlphaNumPlus ['-','_']
|
|||||||
. Text.replace "î" "i"
|
. Text.replace "î" "i"
|
||||||
. Text.replace "ì" "i"
|
. Text.replace "ì" "i"
|
||||||
. Text.replace "í" "i"
|
. Text.replace "í" "i"
|
||||||
. Text.replace "ß" "ss"
|
. Text.replace "ß" "ss"
|
||||||
. Text.replace "ç" "c"
|
. Text.replace "ç" "c"
|
||||||
. Text.replace "ş" "s"
|
. Text.replace "ş" "s"
|
||||||
. Text.replace "ğ" "g"
|
. Text.replace "ğ" "g"
|
||||||
@ -380,10 +380,10 @@ text2Html :: Text -> Html
|
|||||||
text2Html = toHtml
|
text2Html = toHtml
|
||||||
|
|
||||||
citext2Html :: CI Text -> Html
|
citext2Html :: CI Text -> Html
|
||||||
citext2Html = toHtml . CI.original
|
citext2Html = toHtml . CI.original
|
||||||
|
|
||||||
char2Text :: Char -> Text
|
char2Text :: Char -> Text
|
||||||
char2Text c
|
char2Text c
|
||||||
| isSpace c = "<Space>"
|
| isSpace c = "<Space>"
|
||||||
| otherwise = Text.singleton c
|
| otherwise = Text.singleton c
|
||||||
|
|
||||||
@ -425,16 +425,16 @@ withFragment :: Monad m => MForm m (a, WidgetFor site ()) -> Markup -> MForm m (
|
|||||||
withFragment form html = flip fmap form $ over _2 (toWidget html >>)
|
withFragment form html = flip fmap form $ over _2 (toWidget html >>)
|
||||||
|
|
||||||
-- | Burst Text into an unordered set of letters
|
-- | Burst Text into an unordered set of letters
|
||||||
charSet :: Text -> Set Char
|
charSet :: Text -> Set Char
|
||||||
charSet = Text.foldl (flip Set.insert) mempty
|
charSet = Text.foldl (flip Set.insert) mempty
|
||||||
|
|
||||||
-- | Returns Nothing iff both texts are identical,
|
-- | Returns Nothing iff both texts are identical,
|
||||||
-- otherwise a differing character is returned, preferable from the first argument
|
-- otherwise a differing character is returned, preferable from the first argument
|
||||||
textDiff :: Text -> Text -> Maybe Char
|
textDiff :: Text -> Text -> Maybe Char
|
||||||
textDiff (Text.uncons -> xs) (Text.uncons -> ys)
|
textDiff (Text.uncons -> xs) (Text.uncons -> ys)
|
||||||
| Just (x,xt) <- xs
|
| Just (x,xt) <- xs
|
||||||
, Just (y,yt) <- ys
|
, Just (y,yt) <- ys
|
||||||
= if x == y
|
= if x == y
|
||||||
then textDiff xt yt
|
then textDiff xt yt
|
||||||
else Just x
|
else Just x
|
||||||
| otherwise
|
| otherwise
|
||||||
@ -515,17 +515,17 @@ fromText :: (IsString a, Textual t) => t -> a
|
|||||||
fromText = fromString . unpack
|
fromText = fromString . unpack
|
||||||
|
|
||||||
{-
|
{-
|
||||||
-- | Captialize the first character and leave all others as they were
|
-- | Captialize the first character and leave all others as they were
|
||||||
textToCapital :: Text -> Text
|
textToCapital :: Text -> Text
|
||||||
textToCapital s
|
textToCapital s
|
||||||
| Just (h,t) <- Text.uncons s
|
| Just (h,t) <- Text.uncons s
|
||||||
= Text.Cons (Char.toUpper h) t
|
= Text.Cons (Char.toUpper h) t
|
||||||
| otherwise = s
|
| otherwise = s
|
||||||
|
|
||||||
snakecase2camelcase :: Text -> Text
|
snakecase2camelcase :: Text -> Text
|
||||||
snakecase2camelcase t = Text.concat $ map textToCapital words
|
snakecase2camelcase t = Text.concat $ map textToCapital words
|
||||||
where
|
where
|
||||||
words = Text.splitOn '_' t
|
words = Text.splitOn '_' t
|
||||||
-}
|
-}
|
||||||
|
|
||||||
-- | Unlike @Data.Text.unlines, there is no trailing LF at the end
|
-- | Unlike @Data.Text.unlines, there is no trailing LF at the end
|
||||||
@ -606,7 +606,7 @@ roundDiv digits numerator denominator
|
|||||||
-- | @cutOffCoPercent offset full achieved@ returns a value between 0 and 1, measuring how close @achieved@ is to @full@; 0 meaning very and 1 meaning not at all
|
-- | @cutOffCoPercent offset full achieved@ returns a value between 0 and 1, measuring how close @achieved@ is to @full@; 0 meaning very and 1 meaning not at all
|
||||||
--
|
--
|
||||||
-- @offset@ specifies minimum result value, unless the @full@ is equal to @achieved@
|
-- @offset@ specifies minimum result value, unless the @full@ is equal to @achieved@
|
||||||
--
|
--
|
||||||
-- Useful for heat maps, with offset giving a visual step between completed and not yet completed
|
-- Useful for heat maps, with offset giving a visual step between completed and not yet completed
|
||||||
cutOffCoPercent :: Rational -> Rational -> Rational -> Rational
|
cutOffCoPercent :: Rational -> Rational -> Rational -> Rational
|
||||||
cutOffCoPercent (abs -> offset) (abs -> full) (abs -> achieved)
|
cutOffCoPercent (abs -> offset) (abs -> full) (abs -> achieved)
|
||||||
@ -621,7 +621,7 @@ cutOffCoPercent (abs -> offset) (abs -> full) (abs -> achieved)
|
|||||||
-- | @cutOffPercent offset full achieved@ returns a value between 0 and 1, measuring how close @achieved@ is to @full@@; 1 meaning very and 0 meaning not at all
|
-- | @cutOffPercent offset full achieved@ returns a value between 0 and 1, measuring how close @achieved@ is to @full@@; 1 meaning very and 0 meaning not at all
|
||||||
--
|
--
|
||||||
-- @offset@ specifies minimum result value, unless @achieved@ is zero
|
-- @offset@ specifies minimum result value, unless @achieved@ is zero
|
||||||
--
|
--
|
||||||
-- Useful for heat maps, with offset giving a visual step between zero and nonzero
|
-- Useful for heat maps, with offset giving a visual step between zero and nonzero
|
||||||
cutOffPercent :: Rational -> Rational -> Rational -> Rational
|
cutOffPercent :: Rational -> Rational -> Rational -> Rational
|
||||||
cutOffPercent (abs -> offset) (abs -> full) (abs -> achieved)
|
cutOffPercent (abs -> offset) (abs -> full) (abs -> achieved)
|
||||||
@ -686,7 +686,7 @@ mapBoth f ~(a,b) = (f a, f b)
|
|||||||
notNull :: MonoFoldable mono => mono -> Bool
|
notNull :: MonoFoldable mono => mono -> Bool
|
||||||
notNull = not . null
|
notNull = not . null
|
||||||
|
|
||||||
headDef :: a -> [a] -> a
|
headDef :: a -> [a] -> a
|
||||||
headDef _ (h:_) = h
|
headDef _ (h:_) = h
|
||||||
headDef d _ = d
|
headDef d _ = d
|
||||||
|
|
||||||
@ -725,7 +725,7 @@ insertAttr attr valu = aux
|
|||||||
| attr==a = (a, Text.append valu $ Text.cons ' ' v) : t
|
| attr==a = (a, Text.append valu $ Text.cons ' ' v) : t
|
||||||
| otherwise = p : aux t
|
| otherwise = p : aux t
|
||||||
-- Could be implemented using updateAssoc like so, but would add superfluous space at the end:
|
-- Could be implemented using updateAssoc like so, but would add superfluous space at the end:
|
||||||
-- insertAttr attr valu = adjustAssoc (Text.append valu . Text.cons ' ') attr
|
-- insertAttr attr valu = adjustAssoc (Text.append valu . Text.cons ' ') attr
|
||||||
|
|
||||||
-- | Insert key-value pair into association list.
|
-- | Insert key-value pair into association list.
|
||||||
-- If the new value is null/mempty, the first occurrence of the key is removed. (Unlike Data.Map.insert)
|
-- If the new value is null/mempty, the first occurrence of the key is removed. (Unlike Data.Map.insert)
|
||||||
@ -733,13 +733,13 @@ insertAttr attr valu = aux
|
|||||||
-- Note: Avoid association lists, if possible. See GHC.Data.List.SetOps
|
-- Note: Avoid association lists, if possible. See GHC.Data.List.SetOps
|
||||||
-- Some of our libraries use association lists for very few keys.
|
-- Some of our libraries use association lists for very few keys.
|
||||||
insertAssoc :: (Eq k, MonoFoldable v) => k -> v -> [(k,v)] -> [(k,v)]
|
insertAssoc :: (Eq k, MonoFoldable v) => k -> v -> [(k,v)] -> [(k,v)]
|
||||||
insertAssoc key val = aux
|
insertAssoc key val = aux
|
||||||
where
|
where
|
||||||
aux [] = mbcons []
|
aux [] = mbcons []
|
||||||
aux (p@(k,_) : t)
|
aux (p@(k,_) : t)
|
||||||
| key == k = mbcons t
|
| key == k = mbcons t
|
||||||
| otherwise = p : aux t
|
| otherwise = p : aux t
|
||||||
mbcons t
|
mbcons t
|
||||||
| onull val = t
|
| onull val = t
|
||||||
| otherwise = (key,val) : t
|
| otherwise = (key,val) : t
|
||||||
|
|
||||||
@ -804,7 +804,7 @@ withoutSubsequenceBy cmp = go []
|
|||||||
pattern NonEmpty :: forall a. a -> [a] -> NonEmpty a
|
pattern NonEmpty :: forall a. a -> [a] -> NonEmpty a
|
||||||
pattern NonEmpty x xs = x :| xs
|
pattern NonEmpty x xs = x :| xs
|
||||||
{-# COMPLETE NonEmpty #-}
|
{-# COMPLETE NonEmpty #-}
|
||||||
|
|
||||||
checkAsc :: Ord a => [a] -> Bool
|
checkAsc :: Ord a => [a] -> Bool
|
||||||
checkAsc (x:r@(y:_)) = x<=y && checkAsc r
|
checkAsc (x:r@(y:_)) = x<=y && checkAsc r
|
||||||
checkAsc _ = True
|
checkAsc _ = True
|
||||||
@ -825,7 +825,7 @@ infixl 5 !!!
|
|||||||
(!!!) m k = fromMaybe mempty $ Map.lookup k m
|
(!!!) m k = fromMaybe mempty $ Map.lookup k m
|
||||||
|
|
||||||
lookupSome :: (Monad m, Ord k, Monoid (m v)) => Map k (m v) -> m k -> m v
|
lookupSome :: (Monad m, Ord k, Monoid (m v)) => Map k (m v) -> m k -> m v
|
||||||
-- lookupSome :: Ord k => Map k [v] -> [k] -> [v]
|
-- lookupSome :: Ord k => Map k [v] -> [k] -> [v]
|
||||||
-- lookupSome m ks = ks >>= (m !!!)
|
-- lookupSome m ks = ks >>= (m !!!)
|
||||||
lookupSome = (=<<) . (!!!)
|
lookupSome = (=<<) . (!!!)
|
||||||
|
|
||||||
@ -842,7 +842,7 @@ maybeMap :: IsMap p => ContainerKey p -> Maybe (MapValue p) -> p
|
|||||||
maybeMap k = foldMap (singletonMap k)
|
maybeMap k = foldMap (singletonMap k)
|
||||||
|
|
||||||
maybeMapWith :: IsMap p => (t -> MapValue p) -> ContainerKey p -> Maybe t -> p
|
maybeMapWith :: IsMap p => (t -> MapValue p) -> ContainerKey p -> Maybe t -> p
|
||||||
maybeMapWith f k = foldMap $ singletonMap k . f
|
maybeMapWith f k = foldMap $ singletonMap k . f
|
||||||
|
|
||||||
-- | Counts how often a value appears in a map (not derived from invertMap for efficiency reasons)
|
-- | Counts how often a value appears in a map (not derived from invertMap for efficiency reasons)
|
||||||
countMapElems :: (Ord v) => Map k v -> Map v Int
|
countMapElems :: (Ord v) => Map k v -> Map v Int
|
||||||
@ -905,7 +905,7 @@ toNothingS = const Nothing
|
|||||||
eq2nothing :: Eq a => (Maybe a, Maybe a) -> (Maybe a, Maybe a)
|
eq2nothing :: Eq a => (Maybe a, Maybe a) -> (Maybe a, Maybe a)
|
||||||
eq2nothing (mx@(Just x), Just y) | x==y = (mx, Nothing)
|
eq2nothing (mx@(Just x), Just y) | x==y = (mx, Nothing)
|
||||||
eq2nothing p = p
|
eq2nothing p = p
|
||||||
|
|
||||||
-- replaced by a more general formulation, see canonical
|
-- replaced by a more general formulation, see canonical
|
||||||
-- null2nothing :: MonoFoldable a => Maybe a -> Maybe a
|
-- null2nothing :: MonoFoldable a => Maybe a -> Maybe a
|
||||||
-- null2nothing (Just x) | null x = Nothing
|
-- null2nothing (Just x) | null x = Nothing
|
||||||
@ -963,6 +963,7 @@ maybeT x m = runMaybeT m >>= maybe x return
|
|||||||
maybeT_ :: Monad m => MaybeT m () -> m ()
|
maybeT_ :: Monad m => MaybeT m () -> m ()
|
||||||
maybeT_ = void . runMaybeT
|
maybeT_ = void . runMaybeT
|
||||||
|
|
||||||
|
-- Note: for MaybeT, hoistMaybe is more general than the equivalent MaybeT . pure, but also leads to much worse error messages
|
||||||
hoistMaybe :: MonadPlus m => Maybe a -> m a
|
hoistMaybe :: MonadPlus m => Maybe a -> m a
|
||||||
-- ^ `hoist` regarding `Maybe` as if identical to @MaybeT Identity@
|
-- ^ `hoist` regarding `Maybe` as if identical to @MaybeT Identity@
|
||||||
hoistMaybe = maybe mzero return
|
hoistMaybe = maybe mzero return
|
||||||
@ -1020,7 +1021,7 @@ maybeThrowM = fromMaybeM . throwM
|
|||||||
|
|
||||||
maybeMapM :: Applicative m => (a -> m (Maybe b)) -> [a] -> m [b]
|
maybeMapM :: Applicative m => (a -> m (Maybe b)) -> [a] -> m [b]
|
||||||
maybeMapM f = foldr go (pure [])
|
maybeMapM f = foldr go (pure [])
|
||||||
where
|
where
|
||||||
go = liftA2 (maybe id (:)) . f
|
go = liftA2 (maybe id (:)) . f
|
||||||
|
|
||||||
mapMaybeM :: ( Monad m
|
mapMaybeM :: ( Monad m
|
||||||
@ -1039,14 +1040,14 @@ forMaybeM = flip mapMaybeM
|
|||||||
|
|
||||||
-- | Only execute second action if the first does not produce a result
|
-- | Only execute second action if the first does not produce a result
|
||||||
altM :: Monad m => m (Maybe a) -> m (Maybe a) -> m (Maybe a)
|
altM :: Monad m => m (Maybe a) -> m (Maybe a) -> m (Maybe a)
|
||||||
altM ma mb = ma >>= \case
|
altM ma mb = ma >>= \case
|
||||||
Nothing -> mb
|
Nothing -> mb
|
||||||
res -> return res
|
res -> return res
|
||||||
|
|
||||||
-- | Map f and get the first Just
|
-- | Map f and get the first Just
|
||||||
firstJust :: MonoFoldable mono => (Element mono -> Maybe a) -> mono -> Maybe a
|
firstJust :: MonoFoldable mono => (Element mono -> Maybe a) -> mono -> Maybe a
|
||||||
firstJust f = foldr go Nothing
|
firstJust f = foldr go Nothing
|
||||||
where
|
where
|
||||||
-- go :: a -> Maybe b -> Maybe b
|
-- go :: a -> Maybe b -> Maybe b
|
||||||
go x Nothing = f x
|
go x Nothing = f x
|
||||||
go _ res = res
|
go _ res = res
|
||||||
@ -1057,7 +1058,7 @@ firstJust f = foldr go Nothing
|
|||||||
-- Copied from GHC.Data.Maybe, which could not be imported somehow.
|
-- Copied from GHC.Data.Maybe, which could not be imported somehow.
|
||||||
-- HOWEVER, this function counterintuitively forces the entire foldable!
|
-- HOWEVER, this function counterintuitively forces the entire foldable!
|
||||||
-- firstJustM :: (Monad m, Foldable f) => f (m (Maybe a)) -> m (Maybe a)
|
-- firstJustM :: (Monad m, Foldable f) => f (m (Maybe a)) -> m (Maybe a)
|
||||||
-- firstJustM = foldlM go Nothing
|
-- firstJustM = foldlM go Nothing
|
||||||
-- where
|
-- where
|
||||||
-- go :: Monad m => Maybe a -> m (Maybe a) -> m (Maybe a)
|
-- go :: Monad m => Maybe a -> m (Maybe a) -> m (Maybe a)
|
||||||
-- go Nothing action = action
|
-- go Nothing action = action
|
||||||
@ -1068,28 +1069,28 @@ firstJustM :: (Monad m, Foldable f) => f (m (Maybe a)) -> m (Maybe a)
|
|||||||
firstJustM = Fold.foldr go (return Nothing)
|
firstJustM = Fold.foldr go (return Nothing)
|
||||||
where
|
where
|
||||||
go :: Monad m => m (Maybe a) -> m (Maybe a) -> m (Maybe a)
|
go :: Monad m => m (Maybe a) -> m (Maybe a) -> m (Maybe a)
|
||||||
go n p = n >>= \case {Nothing -> p; res -> return res}
|
go n p = n >>= \case {Nothing -> p; res -> return res}
|
||||||
|
|
||||||
-- firstJustM1 :: (Monad m, MonoFoldable mono, Element mono ~ m (Maybe a)) => mono -> m (Maybe a)
|
-- firstJustM1 :: (Monad m, MonoFoldable mono, Element mono ~ m (Maybe a)) => mono -> m (Maybe a)
|
||||||
-- firstJustM1 = foldr go (return Nothing)
|
-- firstJustM1 = foldr go (return Nothing)
|
||||||
-- where
|
-- where
|
||||||
-- go n p = n >>= \case {Nothing -> p; res -> return res}
|
-- go n p = n >>= \case {Nothing -> p; res -> return res}
|
||||||
|
|
||||||
|
|
||||||
-- | Run the maybe computation repeatedly until the first Just is returned
|
-- | Run the maybe computation repeatedly until the first Just is returned
|
||||||
-- or the number of maximum retries is exhausted.
|
-- or the number of maximum retries is exhausted.
|
||||||
-- So like Control.Monad.Loops.untilJust, but with a maximum number of attempts.
|
-- So like Control.Monad.Loops.untilJust, but with a maximum number of attempts.
|
||||||
untilJustMaxM :: Monad m => Int -> m (Maybe a) -> m (Maybe a)
|
untilJustMaxM :: Monad m => Int -> m (Maybe a) -> m (Maybe a)
|
||||||
untilJustMaxM nmax act = go 0
|
untilJustMaxM nmax act = go 0
|
||||||
where
|
where
|
||||||
go n | n >= nmax = return Nothing
|
go n | n >= nmax = return Nothing
|
||||||
| otherwise = do
|
| otherwise = do
|
||||||
x <- act
|
x <- act
|
||||||
case x of
|
case x of
|
||||||
Nothing -> go $ succ n
|
Nothing -> go $ succ n
|
||||||
res@(Just _) -> return res
|
res@(Just _) -> return res
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
------------
|
------------
|
||||||
-- Either --
|
-- Either --
|
||||||
------------
|
------------
|
||||||
@ -1111,8 +1112,8 @@ whenIsRight (Right x) f = f x
|
|||||||
whenIsRight (Left _) _ = pure ()
|
whenIsRight (Left _) _ = pure ()
|
||||||
|
|
||||||
{- Just a reminder for Steffen:
|
{- Just a reminder for Steffen:
|
||||||
mapLeft :: (a -> c) -> Either a b -> Either c b
|
mapLeft :: (a -> c) -> Either a b -> Either c b
|
||||||
mapLeft = over _Left
|
mapLeft = over _Left
|
||||||
-}
|
-}
|
||||||
|
|
||||||
throwLeft :: (MonadThrow m, Exception exc) => Either exc a -> m a
|
throwLeft :: (MonadThrow m, Exception exc) => Either exc a -> m a
|
||||||
@ -1137,20 +1138,20 @@ actRight (Right y) f = f y
|
|||||||
|
|
||||||
-- maybeCatchAll :: MonadCatch m => m a -> m (Maybe a)
|
-- maybeCatchAll :: MonadCatch m => m a -> m (Maybe a)
|
||||||
-- maybeCatchAll act = catch (Just <$> act) ignore
|
-- maybeCatchAll act = catch (Just <$> act) ignore
|
||||||
-- where
|
-- where
|
||||||
-- ignore :: Monad m => SomeException -> m (Maybe a)
|
-- ignore :: Monad m => SomeException -> m (Maybe a)
|
||||||
-- ignore _ = return Nothing
|
-- ignore _ = return Nothing
|
||||||
|
|
||||||
-- | Ignore all errors by returning Nothing. (Not sure if this function is a good idea)
|
-- | Ignore all errors by returning Nothing. (Not sure if this function is a good idea)
|
||||||
maybeCatchAll :: MonadCatch m => m (Maybe a) -> m (Maybe a)
|
maybeCatchAll :: MonadCatch m => m (Maybe a) -> m (Maybe a)
|
||||||
maybeCatchAll act = catch act ignore
|
maybeCatchAll act = catch act ignore
|
||||||
where
|
where
|
||||||
ignore :: Monad m => SomeException -> m (Maybe a)
|
ignore :: Monad m => SomeException -> m (Maybe a)
|
||||||
ignore _ = return Nothing
|
ignore _ = return Nothing
|
||||||
|
|
||||||
maybeExceptT :: Monad m => e -> m (Maybe b) -> ExceptT e m b
|
maybeExceptT :: Monad m => e -> m (Maybe b) -> ExceptT e m b
|
||||||
maybeExceptT err act = lift act >>= maybe (throwE err) return
|
maybeExceptT err act = lift act >>= maybe (throwE err) return
|
||||||
|
|
||||||
maybeExceptT' :: Monad m => e -> Maybe b -> ExceptT e m b
|
maybeExceptT' :: Monad m => e -> Maybe b -> ExceptT e m b
|
||||||
maybeExceptT' err = maybe (throwE err) return
|
maybeExceptT' err = maybe (throwE err) return
|
||||||
|
|
||||||
@ -1299,10 +1300,10 @@ continueJust (Just x) f = f x
|
|||||||
continueJust Nothing _ = pure mempty
|
continueJust Nothing _ = pure mempty
|
||||||
|
|
||||||
maybeContinue :: (Monoid b, Monad m) => m (Maybe a) -> (a -> m b) -> m b
|
maybeContinue :: (Monoid b, Monad m) => m (Maybe a) -> (a -> m b) -> m b
|
||||||
maybeContinue mx f = mx >>= \case
|
maybeContinue mx f = mx >>= \case
|
||||||
Nothing -> return mempty
|
Nothing -> return mempty
|
||||||
Just x -> f x
|
Just x -> f x
|
||||||
-}
|
-}
|
||||||
|
|
||||||
ifoldMapM :: (FoldableWithIndex i f, Monad m, Monoid b) => (i -> a -> m b) -> f a -> m b
|
ifoldMapM :: (FoldableWithIndex i f, Monad m, Monoid b) => (i -> a -> m b) -> f a -> m b
|
||||||
ifoldMapM f = ifoldrM (\i x xs -> (<> xs) <$> f i x) mempty
|
ifoldMapM f = ifoldrM (\i x xs -> (<> xs) <$> f i x) mempty
|
||||||
@ -1437,13 +1438,13 @@ tellM = tell <=< lift
|
|||||||
|
|
||||||
tellPoint :: forall mono m. (MonadWriter mono m, MonoPointed mono) => Element mono -> m ()
|
tellPoint :: forall mono m. (MonadWriter mono m, MonoPointed mono) => Element mono -> m ()
|
||||||
tellPoint = tell . opoint
|
tellPoint = tell . opoint
|
||||||
|
|
||||||
tellMPoint :: (MonadTrans t, MonadWriter mono (t m), Monad m, MonoPointed mono) => m (Element mono) -> t m ()
|
tellMPoint :: (MonadTrans t, MonadWriter mono (t m), Monad m, MonoPointed mono) => m (Element mono) -> t m ()
|
||||||
tellMPoint = tellM . fmap opoint
|
tellMPoint = tellM . fmap opoint
|
||||||
|
|
||||||
class IsWriterT t where
|
class IsWriterT t where
|
||||||
runWriterT' :: (Monad m, Monoid w) => t w m a -> m (a, w)
|
runWriterT' :: (Monad m, Monoid w) => t w m a -> m (a, w)
|
||||||
mapWriterT' :: (m (a, w) -> n (b, w')) -> t w m a -> t w' n b
|
mapWriterT' :: (m (a, w) -> n (b, w')) -> t w m a -> t w' n b
|
||||||
instance IsWriterT Strict.WriterT where
|
instance IsWriterT Strict.WriterT where
|
||||||
runWriterT' = Strict.runWriterT
|
runWriterT' = Strict.runWriterT
|
||||||
mapWriterT' = Strict.mapWriterT
|
mapWriterT' = Strict.mapWriterT
|
||||||
@ -1549,7 +1550,7 @@ data CustomHeader
|
|||||||
| HeaderAlerts
|
| HeaderAlerts
|
||||||
| HeaderDBTableCanonicalURL
|
| HeaderDBTableCanonicalURL
|
||||||
| HeaderDryRun
|
| HeaderDryRun
|
||||||
| HeaderUploadToken
|
| HeaderUploadToken
|
||||||
deriving (Eq, Ord, Enum, Bounded, Read, Show, Generic)
|
deriving (Eq, Ord, Enum, Bounded, Read, Show, Generic)
|
||||||
|
|
||||||
instance Universe CustomHeader
|
instance Universe CustomHeader
|
||||||
@ -1872,8 +1873,8 @@ pickBetter x y crit
|
|||||||
| cx == cy = Nothing
|
| cx == cy = Nothing
|
||||||
| cx = Just x
|
| cx = Just x
|
||||||
| otherwise = Just y
|
| otherwise = Just y
|
||||||
where
|
where
|
||||||
cx = crit x
|
cx = crit x
|
||||||
cy = crit y
|
cy = crit y
|
||||||
|
|
||||||
reverseOrdering :: Ordering -> Ordering
|
reverseOrdering :: Ordering -> Ordering
|
||||||
@ -1940,7 +1941,7 @@ makePrisms ''MergeHashMap
|
|||||||
makeWrapped ''MergeHashMap
|
makeWrapped ''MergeHashMap
|
||||||
|
|
||||||
type instance Element (MergeHashMap k v) = v
|
type instance Element (MergeHashMap k v) = v
|
||||||
|
|
||||||
instance MonoFoldable (MergeHashMap k v)
|
instance MonoFoldable (MergeHashMap k v)
|
||||||
instance MonoFunctor (MergeHashMap k v)
|
instance MonoFunctor (MergeHashMap k v)
|
||||||
instance MonoTraversable (MergeHashMap k v)
|
instance MonoTraversable (MergeHashMap k v)
|
||||||
@ -1994,7 +1995,7 @@ makePrisms ''MergeMap
|
|||||||
makeWrapped ''MergeMap
|
makeWrapped ''MergeMap
|
||||||
|
|
||||||
type instance Element (MergeMap k v) = v
|
type instance Element (MergeMap k v) = v
|
||||||
|
|
||||||
instance MonoFoldable (MergeMap k v)
|
instance MonoFoldable (MergeMap k v)
|
||||||
instance MonoFunctor (MergeMap k v)
|
instance MonoFunctor (MergeMap k v)
|
||||||
instance MonoTraversable (MergeMap k v)
|
instance MonoTraversable (MergeMap k v)
|
||||||
@ -2035,7 +2036,7 @@ instance (Ord k, FromJSON v, FromJSONKey k, Semigroup v) => FromJSON (MergeMap k
|
|||||||
|
|
||||||
parseJSONElemAtIndex :: (Value -> Aeson.Parser a) -> Int -> Vector Value -> Aeson.Parser a
|
parseJSONElemAtIndex :: (Value -> Aeson.Parser a) -> Int -> Vector Value -> Aeson.Parser a
|
||||||
parseJSONElemAtIndex p idx ary = p (V.unsafeIndex ary idx) Aeson.<?> Aeson.Index idx
|
parseJSONElemAtIndex p idx ary = p (V.unsafeIndex ary idx) Aeson.<?> Aeson.Index idx
|
||||||
|
|
||||||
--------------
|
--------------
|
||||||
-- FilePath --
|
-- FilePath --
|
||||||
--------------
|
--------------
|
||||||
@ -2061,7 +2062,7 @@ makePrisms ''ExitCase
|
|||||||
---------------
|
---------------
|
||||||
|
|
||||||
-- | Bad hack class for datatypes that have multiple inequal representations which ought to be identical, i.e. Just "" ~= Nothing
|
-- | Bad hack class for datatypes that have multiple inequal representations which ought to be identical, i.e. Just "" ~= Nothing
|
||||||
class Canonical a where
|
class Canonical a where
|
||||||
canonical :: a -> a
|
canonical :: a -> a
|
||||||
|
|
||||||
|
|
||||||
@ -2071,8 +2072,8 @@ instance {-# OVERLAPPABLE #-} MonoFoldable mono => Canonical (Maybe mono) where
|
|||||||
|
|
||||||
{-
|
{-
|
||||||
instance {-# OVERLAPPABLE #-} (Canonical mono, MonoFoldable mono, Eq mono) => Canonical (Maybe mono) where
|
instance {-# OVERLAPPABLE #-} (Canonical mono, MonoFoldable mono, Eq mono) => Canonical (Maybe mono) where
|
||||||
canonical r@(Just t) = let c = canonical t
|
canonical r@(Just t) = let c = canonical t
|
||||||
in if null c then Nothing else
|
in if null c then Nothing else
|
||||||
if t==c then r else Just c
|
if t==c then r else Just c
|
||||||
canonical other = other
|
canonical other = other
|
||||||
-}
|
-}
|
||||||
|
|||||||
@ -66,7 +66,7 @@ fillDb = do
|
|||||||
n_day n = addBDays n $ utctDay now
|
n_day n = addBDays n $ utctDay now
|
||||||
n_day' n = now { utctDay = n_day n }
|
n_day' n = now { utctDay = n_day n }
|
||||||
(currentYear, _currentMonth, _currentDay) = toGregorian $ utctDay now
|
(currentYear, _currentMonth, _currentDay) = toGregorian $ utctDay now
|
||||||
currentTerm = TermIdentifier currentYear
|
currentTerm = TermIdentifier currentYear
|
||||||
nextTerm n = toEnum . (+n) $ fromEnum currentTerm
|
nextTerm n = toEnum . (+n) $ fromEnum currentTerm
|
||||||
|
|
||||||
termTime :: TermIdentifier -- ^ Term
|
termTime :: TermIdentifier -- ^ Term
|
||||||
@ -572,13 +572,13 @@ fillDb = do
|
|||||||
Just middleName' -> repack [st|#{firstName}.#{middleName'}.#{userSurname}@example.invalid|]
|
Just middleName' -> repack [st|#{firstName}.#{middleName'}.#{userSurname}@example.invalid|]
|
||||||
Nothing -> repack [st|#{firstName}.#{userSurname}@example.invalid|]
|
Nothing -> repack [st|#{firstName}.#{userSurname}@example.invalid|]
|
||||||
userEmail' :: CI Text
|
userEmail' :: CI Text
|
||||||
userEmail' = CI.mk $ case firstName of
|
userEmail' = CI.mk $ case firstName of
|
||||||
"James" -> userIdent
|
"James" -> userIdent
|
||||||
"John" -> userIdent
|
"John" -> userIdent
|
||||||
"Elizabeth" -> "AVSID:" <> userMatrikelnummer'
|
"Elizabeth" -> "AVSID:" <> userMatrikelnummer'
|
||||||
_ -> "E" <> userMatrikelnummer' <> "@fraport.de"
|
_ -> "E" <> userMatrikelnummer' <> "@fraport.de"
|
||||||
userDisplayEmail' :: CI Text
|
userDisplayEmail' :: CI Text
|
||||||
userDisplayEmail' = CI.mk $ case userSurname of
|
userDisplayEmail' = CI.mk $ case userSurname of
|
||||||
"Walker" -> "AVSNO:" <> userMatrikelnummer'
|
"Walker" -> "AVSNO:" <> userMatrikelnummer'
|
||||||
"Clark" -> "E" <> userMatrikelnummer' <> "@fraport.de"
|
"Clark" -> "E" <> userMatrikelnummer' <> "@fraport.de"
|
||||||
"Jackson" -> ""
|
"Jackson" -> ""
|
||||||
@ -591,12 +591,12 @@ fillDb = do
|
|||||||
-- | otherwise
|
-- | otherwise
|
||||||
-- = []
|
-- = []
|
||||||
-- matrikel <- toMatrikel <$> getRandomRs (0 :: Int, 9 :: Int)
|
-- matrikel <- toMatrikel <$> getRandomRs (0 :: Int, 9 :: Int)
|
||||||
baseMatrikel <- getRandomR (10000 :: Int, 999999 :: Int)
|
baseMatrikel <- getRandomR (10000 :: Int, 999999 :: Int)
|
||||||
let matrikel = tshow <$> [baseMatrikel..] List.\\ [6969, 669966, 996699]
|
let matrikel = tshow <$> [baseMatrikel..] List.\\ [6969, 669966, 996699]
|
||||||
manyUsers <- insertMany . getZipList $ manyUser <$> ZipList ((,,) <$> firstNames <*> middlenames <*> surnames) <*> ZipList matrikel
|
manyUsers <- insertMany . getZipList $ manyUser <$> ZipList ((,,) <$> firstNames <*> middlenames <*> surnames) <*> ZipList matrikel
|
||||||
matUsers <- selectList [UserMatrikelnummer !=. Nothing] []
|
matUsers <- selectList [UserMatrikelnummer !=. Nothing] []
|
||||||
insertMany_ [UserAvs (AvsPersonId n) uid n now Nothing Nothing Nothing Nothing | Entity uid User{userMatrikelnummer = fmap readMay -> Just (Just n)} <- matUsers]
|
insertMany_ [UserAvs (AvsPersonId n) uid n now Nothing Nothing Nothing Nothing | Entity uid User{userMatrikelnummer = fmap readMay -> Just (Just n)} <- matUsers]
|
||||||
|
|
||||||
let tmin = -1
|
let tmin = -1
|
||||||
tmax = 2
|
tmax = 2
|
||||||
trange = [tmin..tmax]
|
trange = [tmin..tmax]
|
||||||
@ -692,26 +692,26 @@ fillDb = do
|
|||||||
, UserSupervisor gkleen fhamann False (Just fraGround) (Just "Staff")
|
, UserSupervisor gkleen fhamann False (Just fraGround) (Just "Staff")
|
||||||
, UserSupervisor gkleen gkleen True (Just fraGround) (Just "Staff")
|
, UserSupervisor gkleen gkleen True (Just fraGround) (Just "Staff")
|
||||||
, UserSupervisor tinaTester tinaTester False Nothing (Just "Staff")
|
, UserSupervisor tinaTester tinaTester False Nothing (Just "Staff")
|
||||||
]
|
]
|
||||||
++ take 444 [ UserSupervisor fhamann uid True Nothing (Just $ tshow SupervisorReasonCompanyDefault) | Entity uid _ <- matUsers, uid /= jost]
|
++ take 444 [ UserSupervisor fhamann uid True Nothing (Just $ tshow SupervisorReasonCompanyDefault) | Entity uid _ <- matUsers, uid /= jost]
|
||||||
++ take 123 [ UserSupervisor gkleen uid True Nothing Nothing | Entity uid _ <- drop 369 matUsers ]
|
++ take 123 [ UserSupervisor gkleen uid True Nothing Nothing | Entity uid _ <- drop 369 matUsers ]
|
||||||
++ take 11 [ UserSupervisor jost uid False Nothing (Just $ tshow SupervisorReasonCompanyDefault) | Entity uid _ <- drop 501 matUsers ]
|
++ take 11 [ UserSupervisor jost uid False Nothing (Just $ tshow SupervisorReasonCompanyDefault) | Entity uid _ <- drop 501 matUsers ]
|
||||||
upsertManyWhere supvs [] [] []
|
upsertManyWhere supvs [] [] []
|
||||||
-- insertMany_ supvs -- NOTE: multiple calls like this throw a runtime error!
|
-- insertMany_ supvs -- NOTE: multiple calls like this throw a runtime error!
|
||||||
-- upsertManyWhere supvs [] [] [] -- NOTE: multiple calls like this are ok
|
-- upsertManyWhere supvs [] [] [] -- NOTE: multiple calls like this are ok
|
||||||
-- upsertManyWhere (supvs ++ take 5 (drop 12 [ UserSupervisor jost uid False | Entity uid _ <- drop 501 matUsers ])) -- no duplicates within first argument allowed! (runtime error: ON CONFLICT DO UPDATE command cannot affect row a second time)
|
-- upsertManyWhere (supvs ++ take 5 (drop 12 [ UserSupervisor jost uid False | Entity uid _ <- drop 501 matUsers ])) -- no duplicates within first argument allowed! (runtime error: ON CONFLICT DO UPDATE command cannot affect row a second time)
|
||||||
-- [copyField UserSupervisorRerouteNotifications] [UserSupervisorRerouteNotifications =. True] [UserSupervisorSupervisor ==. jost, UserSupervisorUser <-. [uid | Entity uid _ <- take 3 $ drop 504 matUsers ]] -- does not work!
|
-- [copyField UserSupervisorRerouteNotifications] [UserSupervisorRerouteNotifications =. True] [UserSupervisorSupervisor ==. jost, UserSupervisorUser <-. [uid | Entity uid _ <- take 3 $ drop 504 matUsers ]] -- does not work!
|
||||||
-- let changeSome usr@(UserSupervisor s u _)
|
-- let changeSome usr@(UserSupervisor s u _)
|
||||||
-- | s == jost, u `elem` take 14 [ uid | Entity uid _ <- drop 501 matUsers ] = UserSupervisor s u True
|
-- | s == jost, u `elem` take 14 [ uid | Entity uid _ <- drop 501 matUsers ] = UserSupervisor s u True
|
||||||
-- | otherwise = usr
|
-- | otherwise = usr
|
||||||
-- upsertManyWhere (changeSome <$> (supvs ++ take 5 (drop 12 [ UserSupervisor jost uid False | Entity uid _ <- drop 501 matUsers ]))) -- no duplicates within first argument allowed! (runtime error: ON CONFLICT DO UPDATE command cannot affect row a second time)
|
-- upsertManyWhere (changeSome <$> (supvs ++ take 5 (drop 12 [ UserSupervisor jost uid False | Entity uid _ <- drop 501 matUsers ]))) -- no duplicates within first argument allowed! (runtime error: ON CONFLICT DO UPDATE command cannot affect row a second time)
|
||||||
-- [copyField UserSupervisorRerouteNotifications] [] [UserSupervisorSupervisor ==. jost, UserSupervisorUser <-. [uid | Entity uid _ <- take 3 $ drop 504 matUsers ]] -- probably does the same as the above
|
-- [copyField UserSupervisorRerouteNotifications] [] [UserSupervisorSupervisor ==. jost, UserSupervisorUser <-. [uid | Entity uid _ <- take 3 $ drop 504 matUsers ]] -- probably does the same as the above
|
||||||
-- OBSERVATIONS:
|
-- OBSERVATIONS:
|
||||||
-- - use the 2. argument with `copyField` to overwrite an existing field with the new record value provided in the 1. argument in case of an update
|
-- - use the 2. argument with `copyField` to overwrite an existing field with the new record value provided in the 1. argument in case of an update
|
||||||
-- - use the 3. argument to update a field indepently from the provided records or for computations involving previous values, eg. +=.
|
-- - use the 3. argument to update a field indepently from the provided records or for computations involving previous values, eg. +=.
|
||||||
-- - use the 4. argument to filter both the application of the 2. and 3. argument
|
-- - use the 4. argument to filter both the application of the 2. and 3. argument
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
ifi <- insert' $ School "Institut für Informatik" "IfI" (Just $ 14 * nominalDay) (Just $ 10 * nominalDay) True (ExamModeDNF predDNFFalse) (ExamCloseOnFinished True) SchoolAuthorshipStatementModeOptional (Just ifiAuthorshipStatement) True SchoolAuthorshipStatementModeRequired (Just ifiAuthorshipStatement) False
|
ifi <- insert' $ School "Institut für Informatik" "IfI" (Just $ 14 * nominalDay) (Just $ 10 * nominalDay) True (ExamModeDNF predDNFFalse) (ExamCloseOnFinished True) SchoolAuthorshipStatementModeOptional (Just ifiAuthorshipStatement) True SchoolAuthorshipStatementModeRequired (Just ifiAuthorshipStatement) False
|
||||||
mi <- insert' $ School "Institut für Mathematik" "MI" Nothing Nothing False (ExamModeDNF predDNFFalse) (ExamCloseOnFinished False) SchoolAuthorshipStatementModeNone Nothing True SchoolAuthorshipStatementModeOptional Nothing True
|
mi <- insert' $ School "Institut für Mathematik" "MI" Nothing Nothing False (ExamModeDNF predDNFFalse) (ExamCloseOnFinished False) SchoolAuthorshipStatementModeNone Nothing True SchoolAuthorshipStatementModeOptional Nothing True
|
||||||
@ -719,13 +719,13 @@ fillDb = do
|
|||||||
void . insert' $ UserFunction jost avn SchoolAdmin
|
void . insert' $ UserFunction jost avn SchoolAdmin
|
||||||
void . insert' $ UserFunction gkleen ifi SchoolAdmin
|
void . insert' $ UserFunction gkleen ifi SchoolAdmin
|
||||||
void . insert' $ UserFunction gkleen mi SchoolAdmin
|
void . insert' $ UserFunction gkleen mi SchoolAdmin
|
||||||
-- void . insert' $ UserFunction fhamann ifi SchoolAdmin -- goto-example for non-admin supervisor
|
-- void . insert' $ UserFunction fhamann ifi SchoolAdmin -- goto-example for non-admin supervisor
|
||||||
void . insert' $ UserFunction jost ifi SchoolAdmin
|
void . insert' $ UserFunction jost ifi SchoolAdmin
|
||||||
void . insert' $ UserFunction jost mi SchoolAdmin
|
void . insert' $ UserFunction jost mi SchoolAdmin
|
||||||
void . insert' $ UserFunction svaupel ifi SchoolAdmin
|
void . insert' $ UserFunction svaupel ifi SchoolAdmin
|
||||||
void . insert' $ UserFunction svaupel mi SchoolAdmin
|
void . insert' $ UserFunction svaupel mi SchoolAdmin
|
||||||
void . insert' $ UserFunction gkleen ifi SchoolLecturer
|
void . insert' $ UserFunction gkleen ifi SchoolLecturer
|
||||||
-- void . insert' $ UserFunction fhamann ifi SchoolLecturer -- goto-example for non-admin supervisor
|
-- void . insert' $ UserFunction fhamann ifi SchoolLecturer -- goto-example for non-admin supervisor
|
||||||
void . insert' $ UserFunction jost ifi SchoolLecturer
|
void . insert' $ UserFunction jost ifi SchoolLecturer
|
||||||
void . insert' $ UserFunction svaupel ifi SchoolLecturer
|
void . insert' $ UserFunction svaupel ifi SchoolLecturer
|
||||||
void . insert' $ UserFunction sbarth ifi SchoolLecturer
|
void . insert' $ UserFunction sbarth ifi SchoolLecturer
|
||||||
@ -802,6 +802,8 @@ fillDb = do
|
|||||||
insert_ $ ProblemLog now (toJSON $ AdminProblemNewCompany ffacil ) Nothing Nothing
|
insert_ $ ProblemLog now (toJSON $ AdminProblemNewCompany ffacil ) Nothing Nothing
|
||||||
insert_ $ ProblemLog now (toJSON $ AdminProblemSupervisorNewCompany fhamann fraportAg ffacil True ) Nothing Nothing
|
insert_ $ ProblemLog now (toJSON $ AdminProblemSupervisorNewCompany fhamann fraportAg ffacil True ) Nothing Nothing
|
||||||
insert_ $ ProblemLog now (toJSON $ AdminProblemSupervisorNewCompany gkleen ffacil fraGround False) Nothing Nothing
|
insert_ $ ProblemLog now (toJSON $ AdminProblemSupervisorNewCompany gkleen ffacil fraGround False) Nothing Nothing
|
||||||
|
insert_ $ ProblemLog now (toJSON $ AdminProblemCompanySuperiorChange jost fraportAg (Just gkleen)) Nothing Nothing
|
||||||
|
insert_ $ ProblemLog now (toJSON $ AdminProblemCompanySuperiorChange fhamann fraGround Nothing) Nothing Nothing
|
||||||
insert_ $ ProblemLog now (toJSON $ AdminProblemUnknown "This is a test problem only.") Nothing Nothing
|
insert_ $ ProblemLog now (toJSON $ AdminProblemUnknown "This is a test problem only.") Nothing Nothing
|
||||||
|
|
||||||
let
|
let
|
||||||
@ -1024,7 +1026,7 @@ fillDb = do
|
|||||||
, courseDeregisterUntil = jtt TermDayLectureStart 5 (Just Monday) toMidnight
|
, courseDeregisterUntil = jtt TermDayLectureStart 5 (Just Monday) toMidnight
|
||||||
, courseRegisterSecret = Nothing
|
, courseRegisterSecret = Nothing
|
||||||
, courseMaterialFree = True
|
, courseMaterialFree = True
|
||||||
}
|
}
|
||||||
insert_ $ CourseEdit jost now c
|
insert_ $ CourseEdit jost now c
|
||||||
when (tyear >= currentYear) $ insert_ $ CourseQualification c qid_f 2
|
when (tyear >= currentYear) $ insert_ $ CourseQualification c qid_f 2
|
||||||
when (tyear >= succ currentYear) $ insert_ $ CourseQualification c qid_r 3
|
when (tyear >= succ currentYear) $ insert_ $ CourseQualification c qid_r 3
|
||||||
|
|||||||
Reference in New Issue
Block a user