Merge branch 'master' into fradrive/tutorial-overhaul

This commit is contained in:
Steffen Jost 2023-02-14 13:23:00 +01:00
commit 8c7158eac9
46 changed files with 139 additions and 139 deletions

View File

@ -12,9 +12,9 @@ CommUndisclosedRecipients: Verborgene Empfänger:innen
CommAllRecipients: alle-empfaenger CommAllRecipients: alle-empfaenger
CommAllRecipientsSheet: Empfänger:innen CommAllRecipientsSheet: Empfänger:innen
ResetPassword: FRADrive-Passwort ändern bzw. setzen ResetPassword: FRADrive-Passwort ändern bzw. setzen
MailSubjectChangeUserDisplayEmail: Diese E-Mail-Adresse in FRADrive veröffentlichen MailSubjectChangeUserDisplayEmail: E-Mail-Adresse in FRADrive verwenden
MailIntroChangeUserDisplayEmail displayEmail@UserEmail: Der oben genannte Benutzer/Die oben genannte Benutzerin möchte „#{displayEmail}“ als öffentliche Adresse, assoziiert mit sich selbst, angeben. Wenn Sie diese Aktion nicht selbst ausgelöst haben, ignorieren Sie diese Mitteilung bitte! MailIntroChangeUserDisplayEmail displayEmail@UserEmail: Der oben genannte Benutzer/Die oben genannte Benutzerin möchte „#{displayEmail}“ als E-Mail-Adresse in FRADrive verwenden. Wenn Sie diese Aktion nicht selbst ausgelöst haben, ignorieren Sie diese Mitteilung bitte!
MailTitleChangeUserDisplayEmail displayName@Text: #{displayName} möchte diese E-Mail-Adresse in FRADrive veröffentlichen MailTitleChangeUserDisplayEmail displayName@Text: #{displayName} möchte diese E-Mail-Adresse in FRADrive verwenden
CommCourseSubject: Kursmitteilung CommCourseSubject: Kursmitteilung
InvitationAcceptDecline: Einladung annehmen/ablehnen InvitationAcceptDecline: Einladung annehmen/ablehnen
InvitationFromTip displayName@Text: Sie erhalten diese Einladung, weil #{displayName} ihren Versand in FRADrive ausgelöst hat. InvitationFromTip displayName@Text: Sie erhalten diese Einladung, weil #{displayName} ihren Versand in FRADrive ausgelöst hat.

View File

@ -12,9 +12,9 @@ CommUndisclosedRecipients: Undisclosed recipients
CommAllRecipients: all-recipients CommAllRecipients: all-recipients
CommAllRecipientsSheet: Recipients CommAllRecipientsSheet: Recipients
ResetPassword: Reselt FRADrive password ResetPassword: Reselt FRADrive password
MailSubjectChangeUserDisplayEmail: Publishing this email address in FRADrive MailSubjectChangeUserDisplayEmail: Set email address in FRADrive
MailIntroChangeUserDisplayEmail displayEmail: The user mentioned above wants to publish “#{displayEmail}” as their own email address. If you have not caused this email to be sent, please ignore it! MailIntroChangeUserDisplayEmail displayEmail: The user mentioned above wants to set “#{displayEmail}” as their own email address. If you have not caused this email to be sent, please ignore it!
MailTitleChangeUserDisplayEmail displayName: #{displayName} wants to publish this email address as their own in FRADrive MailTitleChangeUserDisplayEmail displayName: #{displayName} wants to set this email address as their own in FRADrive
CommCourseSubject: Course message CommCourseSubject: Course message
InvitationAcceptDecline: Accept/Decline invitation InvitationAcceptDecline: Accept/Decline invitation
InvitationFromTip displayName: You are receiving this invitation because #{displayName} has caused it to be sent from within FRADrive. InvitationFromTip displayName: You are receiving this invitation because #{displayName} has caused it to be sent from within FRADrive.

View File

@ -8,9 +8,11 @@ FormPersonalAppearance: Öffentliche Daten
UserDisplayName: Angezeigter Name UserDisplayName: Angezeigter Name
UserDisplayNameInvalid: Angezeigter Name erfüllt nicht die Vorgaben UserDisplayNameInvalid: Angezeigter Name erfüllt nicht die Vorgaben
UserDisplayNameRulesBelow: Vorgaben für den angezeigten Namen finden sich weiter unten auf der Seite UserDisplayNameRulesBelow: Vorgaben für den angezeigten Namen finden sich weiter unten auf der Seite
UserDisplayEmail: Angezeigte E-Mail-Adresse UserSystemEmail: System E-Mail Adresse
UserDisplayEmailTip: Diese Adresse wird in öffentlich zugänglichen Teilen des Systems im Zusammenhang mit Ihrem Namen angezeigt. Benachrichtigungen und andere Kommunikation von Uni2work und Nutzer:innen mit erweiterten Rechten erhalten sie stets, unabhängig von dieser Einstellung, an die in Ihren Persönlichen Daten hinterlegte primäre Adresse. UserDisplayEmail: E-Mail-Adresse
UserDisplayEmailChangeSent displayEmail@UserEmail: Anweisungen zum Ändern der angezeigten E-Mail-Adresse wurden an „#{displayEmail}” versandt UserDisplayEmailTip: Diese Adresse wird in öffentlich zugänglichen Teilen des Systems im Zusammenhang mit Ihrem Namen angezeigt. Falls diese ungültig ist gehen Benachrichtigungen an ihre System E-Mail-Adresse.
UserDisplayEmailChangeSent displayEmail@UserEmail: Anweisungen zum Ändern der E-Mail-Adresse wurden an „#{displayEmail}” versandt
UserDisplayEmailChanged: Öffentliche E-Mail-Adresse erfolgreich gesetzt
FormCosmetics: Oberfläche FormCosmetics: Oberfläche
@ -94,7 +96,6 @@ ProfileLdapPrimaryKey: LDAP-Primärschlüssel
NotificationSettingsUpdate: Benachrichtigungs-Einstellungen erfolgreich gespeichert NotificationSettingsUpdate: Benachrichtigungs-Einstellungen erfolgreich gespeichert
NotificationSettingsHeading displayName@Text: Benachrichtigungs-Einstellungen für #{displayName} NotificationSettingsHeading displayName@Text: Benachrichtigungs-Einstellungen für #{displayName}
UserDisplayEmailChanged: Öffentliche E-Mail-Adresse erfolgreich gesetzt
FavouriteVisited: Kürzlich besucht FavouriteVisited: Kürzlich besucht
FavouriteParticipant: Ihre Kurse FavouriteParticipant: Ihre Kurse
FavouriteManual: Favoriten FavouriteManual: Favoriten

View File

@ -8,9 +8,11 @@ FormPersonalAppearance: Public data
UserDisplayName: Display name UserDisplayName: Display name
UserDisplayNameInvalid: Display name does not comply with specification UserDisplayNameInvalid: Display name does not comply with specification
UserDisplayNameRulesBelow: Specifications of what can be a display name can be found below UserDisplayNameRulesBelow: Specifications of what can be a display name can be found below
UserDisplayEmail: Display email UserSystemEmail: System Email address
UserDisplayEmailTip: This email address may be displayed publicly alongside your display name. Notifications and other communication from Uni2work or users with elevated permissions are always sent to your primary email address as specified under "personal information". UserDisplayEmail: Email
UserDisplayEmailTip: This email address may be displayed publicly alongside your display name. If invalid, notifications will be sent to your system email address instead.
UserDisplayEmailChangeSent displayEmail: Instructions to change your display email have been sent to “#{displayEmail}”. UserDisplayEmailChangeSent displayEmail: Instructions to change your display email have been sent to “#{displayEmail}”.
UserDisplayEmailChanged: Successfully set display email
FormCosmetics: Interface FormCosmetics: Interface
@ -94,7 +96,6 @@ ProfileLdapPrimaryKey: LDAP primary key
NotificationSettingsUpdate: Successfully updated notification settings NotificationSettingsUpdate: Successfully updated notification settings
NotificationSettingsHeading displayName: Notification settings for #{displayName} NotificationSettingsHeading displayName: Notification settings for #{displayName}
UserDisplayEmailChanged: Successfully set display email
FavouriteVisited: Visited FavouriteVisited: Visited
FavouriteParticipant: Your courses FavouriteParticipant: Your courses
FavouriteManual: Favourites FavouriteManual: Favourites

View File

@ -6,8 +6,8 @@ AdminUserTitle: Titel
AdminUserFirstName: Vorname AdminUserFirstName: Vorname
AdminUserSurname: Nachname AdminUserSurname: Nachname
AdminUserDisplayName: Anzeige-Name AdminUserDisplayName: Anzeige-Name
AdminUserEmail: E-Mail-Adresse AdminUserEmail: System E-Mail
AdminUserDisplayEmail: Anzeige-E-Mail AdminUserDisplayEmail: E-Mail-Adresse
AdminUserIdent: Identifikation AdminUserIdent: Identifikation
AdminUserAuth: Authentifizierung AdminUserAuth: Authentifizierung
AdminUserAuthTooltip: Abhängig von der Auswahl werden neue Benutzer über ihr neues FRADrive Konto benachrichtigt. AdminUserAuthTooltip: Abhängig von der Auswahl werden neue Benutzer über ihr neues FRADrive Konto benachrichtigt.

View File

@ -6,8 +6,8 @@ AdminUserTitle: Title
AdminUserFirstName: Given name AdminUserFirstName: Given name
AdminUserSurname: Surname AdminUserSurname: Surname
AdminUserDisplayName: Display name AdminUserDisplayName: Display name
AdminUserEmail: Email address AdminUserEmail: System Email address
AdminUserDisplayEmail: Display email AdminUserDisplayEmail: Email address
AdminUserIdent: Identification AdminUserIdent: Identification
AdminUserAuth: Authentication AdminUserAuth: Authentication
AdminUserAuthTooltip: New users may be notified about their FRADrive account depending on this choice. AdminUserAuthTooltip: New users may be notified about their FRADrive account depending on this choice.

View File

@ -88,7 +88,7 @@ BreadcrumbVersion: Versionsgeschichte
BreadcrumbHelp: Hilfe BreadcrumbHelp: Hilfe
BreadcrumbHealth: Instanz-Zustand BreadcrumbHealth: Instanz-Zustand
BreadcrumbInstance: Instanz-Identifikation BreadcrumbInstance: Instanz-Identifikation
BreadcrumbUserDisplayEmail: Angezeigte E-Mail-Adresse BreadcrumbUserDisplayEmail: E-Mail-Adresse
BreadcrumbProfileData: Persönliche Daten BreadcrumbProfileData: Persönliche Daten
BreadcrumbAuthPreds: Authorisierungseinstellungen BreadcrumbAuthPreds: Authorisierungseinstellungen
BreadcrumbTermShow: Semester BreadcrumbTermShow: Semester

View File

@ -88,7 +88,7 @@ BreadcrumbVersion: Version history
BreadcrumbHelp: Support BreadcrumbHelp: Support
BreadcrumbHealth: Instance health BreadcrumbHealth: Instance health
BreadcrumbInstance: Instance identification BreadcrumbInstance: Instance identification
BreadcrumbUserDisplayEmail: Display email BreadcrumbUserDisplayEmail: Email address
BreadcrumbProfileData: Personal information BreadcrumbProfileData: Personal information
BreadcrumbAuthPreds: Authorisation settings BreadcrumbAuthPreds: Authorisation settings
BreadcrumbTermShow: Semesters BreadcrumbTermShow: Semesters

View File

@ -23,6 +23,7 @@ UserAvs
-- Multiple UserAvsCards per UserAvs is possible and not too uncommon. -- Multiple UserAvsCards per UserAvs is possible and not too uncommon.
-- Purpose of saving cards is to detect external changes in qualifications and postal addresses -- Purpose of saving cards is to detect external changes in qualifications and postal addresses
-- TODO: This table will be deleted if AVS CR3 SCF-165 is implemented
UserAvsCard UserAvsCard
personId AvsPersonId personId AvsPersonId
cardNo AvsFullCardNo cardNo AvsFullCardNo

View File

@ -88,8 +88,8 @@ UserGroupMember
UserCompany UserCompany
user UserId user UserId
company CompanyId OnDeleteCascade OnUpdateCascade company CompanyId OnDeleteCascade OnUpdateCascade
supervisor Bool -- should this user be made supervisor for all _new_ users associated with this company? supervisor Bool default=false -- should this user be made supervisor for all _new_ users associated with this company?
supervisorReroute Bool default=true -- if supervisor is true, should this supervisor receive email for _new_ company users? supervisorReroute Bool default=false -- if supervisor is true, should this supervisor receive email for _new_ company users?
UniqueUserCompany user company -- a user may belong to multiple companies, but to each one only once UniqueUserCompany user company -- a user may belong to multiple companies, but to each one only once
deriving Generic deriving Generic
UserSupervisor UserSupervisor

View File

@ -259,8 +259,8 @@ instance YesodMail UniWorX where
return user return user
let recipUserCompare = mconcat let recipUserCompare = mconcat
[ comparing $ Down . (== recipAddr) . userIdent . entityVal [ comparing $ Down . (== recipAddr) . userIdent . entityVal
, comparing $ Down . (== recipAddr) . userEmail . entityVal
, comparing $ Down . (== recipAddr) . userDisplayEmail . entityVal , comparing $ Down . (== recipAddr) . userDisplayEmail . entityVal
, comparing $ Down . (== recipAddr) . userEmail . entityVal
] ]
return $ if return $ if
| ( bU : us ) <- sortBy recipUserCompare recipUsers | ( bU : us ) <- sortBy recipUserCompare recipUsers

View File

@ -117,7 +117,7 @@ makeCourseForm miButtonAction template = identifyForm FIDcourse . validateFormDB
miCell :: ListPosition -> Either UserEmail UserId -> Maybe (Maybe LecturerType) -> (Text -> Text) -> Form (Maybe LecturerType) miCell :: ListPosition -> Either UserEmail UserId -> Maybe (Maybe LecturerType) -> (Text -> Text) -> Form (Maybe LecturerType)
miCell _ (Right lid) defType nudge = \csrf -> do miCell _ (Right lid) defType nudge = \csrf -> do
(lrwRes,lrwView) <- mreq (selectField optionsFinite) (fslI MsgCourseLecturerType & addName (nudge "lecturer-type")) (join defType) (lrwRes,lrwView) <- mreq (selectField optionsFinite) (fslI MsgCourseLecturerType & addName (nudge "lecturer-type")) (join defType)
User{userEmail, userDisplayName, userSurname} <- liftHandler . runDB $ get404 lid usr <- liftHandler . runDB $ get404 lid
let lrwView' = $(widgetFile "course/lecturerMassInput/cellKnown") let lrwView' = $(widgetFile "course/lecturerMassInput/cellKnown")
return (Just <$> lrwRes,lrwView') return (Just <$> lrwRes,lrwView')
miCell _ (Left lEmail) defType nudge = \csrf -> do miCell _ (Left lEmail) defType nudge = \csrf -> do

View File

@ -168,7 +168,7 @@ getCShowR tid ssh csh = do
tutTutors <- fmap (map $(unValueN 3)) . E.select . E.from $ \(tutor `E.InnerJoin` user) -> do tutTutors <- fmap (map $(unValueN 3)) . E.select . E.from $ \(tutor `E.InnerJoin` user) -> do
E.on $ tutor E.^. TutorUser E.==. user E.^. UserId E.on $ tutor E.^. TutorUser E.==. user E.^. UserId
E.where_ $ tutor E.^. TutorTutorial E.==. E.val tutid E.where_ $ tutor E.^. TutorTutorial E.==. E.val tutid
return (user E.^. UserEmail, user E.^. UserDisplayName, user E.^. UserSurname) return (user E.^. UserDisplayEmail, user E.^. UserDisplayName, user E.^. UserSurname)
return [whamlet| return [whamlet|
$newline never $newline never
<ul .list--iconless .list--inline .list--comma-separated> <ul .list--iconless .list--inline .list--comma-separated>

View File

@ -11,27 +11,24 @@ import Import
import Utils.Form import Utils.Form
import Handler.Utils import Handler.Utils
import Handler.Utils.SheetType import Handler.Utils.SheetType
import Database.Esqueleto.Utils.TH import Handler.Utils.Profile (pickValidEmail)
import Handler.Utils.StudyFeatures
import qualified Database.Esqueleto.Legacy as E import Handler.Submission.List
import qualified Database.Esqueleto.Utils as E
import Database.Persist.Sql (deleteWhereCount)
import Text.Blaze.Html.Renderer.Text (renderHtml)
import Handler.Course.Register import Handler.Course.Register
import Jobs.Queue import Jobs.Queue
import Handler.Submission.List import Database.Persist.Sql (deleteWhereCount)
import Database.Esqueleto.Utils.TH
import qualified Database.Esqueleto.Legacy as E
import qualified Database.Esqueleto.Utils as E
import Handler.Utils.StudyFeatures import Text.Blaze.Html.Renderer.Text (renderHtml)
import qualified Data.Map as Map import qualified Data.Map as Map
import qualified Data.Text as Text import qualified Data.Text as Text
import qualified Data.CaseInsensitive as CI import qualified Data.CaseInsensitive as CI
import qualified Data.Text.Lazy as LT import qualified Data.Text.Lazy as LT
@ -444,9 +441,9 @@ courseUserTutorialsSection (Entity cid Course{..}) (Entity uid _) = do
[whamlet| [whamlet|
$newline never $newline never
<ul .list--iconless .list--inline .list--comma-separated> <ul .list--iconless .list--inline .list--comma-separated>
$forall (Entity _ User{userEmail, userDisplayName, userSurname}) <- tutors $forall (Entity _ usr) <- tutors
<li> <li>
^{nameEmailWidget userEmail userDisplayName userSurname} ^{userEmailWidget usr}
|] |]
, sortable (Just "room") (i18nCell MsgTableTutorialRoom) $ maybe (i18nCell MsgTableTutorialRoomIsUnset) roomReferenceCell . view (_dbrOutput . _1 . _entityVal . _tutorialRoom) , sortable (Just "room") (i18nCell MsgTableTutorialRoom) $ maybe (i18nCell MsgTableTutorialRoomIsUnset) roomReferenceCell . view (_dbrOutput . _1 . _entityVal . _tutorialRoom)
, sortable Nothing (i18nCell MsgTableTutorialTime) $ occurrencesCell . view (_dbrOutput . _1 . _entityVal . _tutorialTime) , sortable Nothing (i18nCell MsgTableTutorialTime) $ occurrencesCell . view (_dbrOutput . _1 . _entityVal . _tutorialTime)

View File

@ -240,7 +240,7 @@ examCorrectorsForm mPrev = wFormToAForm $ do
invWarnMsg <- messageIconI Info IconEmail MsgEmailInvitationWarning invWarnMsg <- messageIconI Info IconEmail MsgEmailInvitationWarning
$(widgetFile "widgets/massinput/examCorrectors/cellInvitation") $(widgetFile "widgets/massinput/examCorrectors/cellInvitation")
miCell' (Right userId) = do miCell' (Right userId) = do
User{..} <- liftHandler . runDB $ get404 userId usr <- liftHandler . runDB $ get404 userId
$(widgetFile "widgets/massinput/examCorrectors/cellKnown") $(widgetFile "widgets/massinput/examCorrectors/cellKnown")
miLayout' :: MassInputLayout ListLength (Either UserEmail UserId) () miLayout' :: MassInputLayout ListLength (Either UserEmail UserId) ()

View File

@ -112,7 +112,7 @@ makeExamOfficeUsersForm template = renderWForm FormStandard $ do
invWarnMsg <- messageIconI Info IconEmail MsgEmailInvitationWarning invWarnMsg <- messageIconI Info IconEmail MsgEmailInvitationWarning
$(widgetFile "widgets/massinput/examOfficeUsers/cellInvitation") $(widgetFile "widgets/massinput/examOfficeUsers/cellInvitation")
miCell' (Right uid) = do miCell' (Right uid) = do
User{..} <- liftHandler . runDB $ getJust uid usr <- liftHandler . runDB $ getJust uid
$(widgetFile "widgets/massinput/examOfficeUsers/cellKnown") $(widgetFile "widgets/massinput/examOfficeUsers/cellKnown")
miButtonAction' :: forall p. PathPiece p => p -> Maybe (SomeRoute UniWorX) miButtonAction' :: forall p. PathPiece p => p -> Maybe (SomeRoute UniWorX)
miButtonAction' frag = Just . SomeRoute $ cRoute :#: frag miButtonAction' frag = Just . SomeRoute $ cRoute :#: frag

View File

@ -100,7 +100,7 @@ externalExamForm template = validateForm validateExternalExam $ \html -> do
invWarnMsg <- messageIconI Info IconEmail MsgEmailInvitationWarning invWarnMsg <- messageIconI Info IconEmail MsgEmailInvitationWarning
$(widgetFile "external-exam/staffMassInput/cellInvitation") $(widgetFile "external-exam/staffMassInput/cellInvitation")
miCell (Right userId) = do miCell (Right userId) = do
User{..} <- liftHandler . runDB $ getJust userId usr <- liftHandler . runDB $ getJust userId
$(widgetFile "external-exam/staffMassInput/cellKnown") $(widgetFile "external-exam/staffMassInput/cellKnown")
miButtonAction :: forall p. PathPiece p => p -> Maybe (SomeRoute UniWorX) miButtonAction :: forall p. PathPiece p => p -> Maybe (SomeRoute UniWorX)
miButtonAction = Just . SomeRoute . (cRoute :#:) miButtonAction = Just . SomeRoute . (cRoute :#:)

View File

@ -452,7 +452,7 @@ mkLmsTable nlimit noffset isAdmin (Entity qid quali) acts cols psValidator = do
doEncode' :: LmsTableData -> LmsTableCsv doEncode' :: LmsTableData -> LmsTableCsv
doEncode' = LmsTableCsv doEncode' = LmsTableCsv
<$> view (resultUser . _entityVal . _userDisplayName) <$> view (resultUser . _entityVal . _userDisplayName)
<*> view (resultUser . _entityVal . _userEmail) <*> view (resultUser . _entityVal . _userDisplayEmail)
<*> view (resultQualUser . _entityVal . _qualificationUserValidUntil) <*> view (resultQualUser . _entityVal . _qualificationUserValidUntil)
<*> view (resultQualUser . _entityVal . _qualificationUserLastRefresh) <*> view (resultQualUser . _entityVal . _qualificationUserLastRefresh)
<*> view (resultQualUser . _entityVal . _qualificationUserFirstHeld) <*> view (resultQualUser . _entityVal . _qualificationUserFirstHeld)

View File

@ -280,7 +280,7 @@ mkPJTable = do
let jobSet = Map.keysSet . Map.filter id $ getDBFormResult (const False) jobMap let jobSet = Map.keysSet . Map.filter id $ getDBFormResult (const False) jobMap
return (act, jobSet) return (act, jobSet)
psValidator = def & defaultSorting [SortAscBy "created"] psValidator = def & defaultSorting [SortAscBy "created"]
& defaultFilter (singletonMap "acknowledged" [toPathPiece False]) -- & defaultFilter (singletonMap "acknowledged" [toPathPiece False]) -- TODO: interferes with sorting!
over _1 postprocess <$> dbTable psValidator DBTable{..} over _1 postprocess <$> dbTable psValidator DBTable{..}
getPrintCenterR, postPrintCenterR :: Handler Html getPrintCenterR, postPrintCenterR :: Handler Html

View File

@ -330,7 +330,7 @@ mkQualificationTable (Entity qid quali) acts cols psValidator = do
doEncode' :: QualificationTableData -> QualificationTableCsv doEncode' :: QualificationTableData -> QualificationTableCsv
doEncode' = QualificationTableCsv doEncode' = QualificationTableCsv
<$> view (resultUser . _entityVal . _userDisplayName) <$> view (resultUser . _entityVal . _userDisplayName)
<*> view (resultUser . _entityVal . _userEmail) <*> view (resultUser . _entityVal . _userDisplayEmail)
<*> view (resultQualUser . _entityVal . _qualificationUserValidUntil) <*> view (resultQualUser . _entityVal . _qualificationUserValidUntil)
<*> view (resultQualUser . _entityVal . _qualificationUserLastRefresh) <*> view (resultQualUser . _entityVal . _qualificationUserLastRefresh)
<*> preview (resultQualUser . _entityVal . _qualificationUserBlockedDue . _Just . _qualificationBlockedDay) <*> preview (resultQualUser . _entityVal . _qualificationUserBlockedDue . _Just . _qualificationBlockedDay)

View File

@ -307,8 +307,8 @@ correctorForm loads' = wFormToAForm $ do
identWidget <- case userIdent of identWidget <- case userIdent of
Left email -> return . toWidget $ mailtoHtml email Left email -> return . toWidget $ mailtoHtml email
Right uid -> do Right uid -> do
User{userEmail, userDisplayName, userSurname} <- liftHandler . runDB $ getJust uid usr <- liftHandler . runDB $ getJust uid
return $ nameEmailWidget userEmail userDisplayName userSurname return $ userEmailWidget usr
invWarnMsg <- messageIconI Info IconEmail MsgEmailInvitationWarning invWarnMsg <- messageIconI Info IconEmail MsgEmailInvitationWarning
return (res, $(widgetFile "sheetCorrectors/cell")) return (res, $(widgetFile "sheetCorrectors/cell"))

View File

@ -231,10 +231,8 @@ assignHandler tid ssh csh cid assignSids = do
-- avoid nestes hamlet $maybe with duplicated $nothing -- avoid nestes hamlet $maybe with duplicated $nothing
getCorrector :: Maybe UserId -> (Widget,Map SheetName SheetCorrector, Text) getCorrector :: Maybe UserId -> (Widget,Map SheetName SheetCorrector, Text)
getCorrector (Just uid) getCorrector (Just uid)
| Just (User{..},loadMap) <- Map.lookup uid correctorMap | Just (usr,loadMap) <- Map.lookup uid correctorMap
= (nameEmailWidget userEmail userDisplayName userSurname, loadMap, userDisplayName) = (userEmailWidget usr, loadMap, usr ^. _userDisplayName)
-- | Just (User{..} ) <- Map.lookup uid lecturerNames
-- = (nameEmailWidget userEmail userDisplayName userSurname, mempty) -- lecturers may also correct in rare cases
getCorrector _ = ([whamlet|_{MsgNoCorrectorAssigned}|], mempty, mempty) getCorrector _ = ([whamlet|_{MsgNoCorrectorAssigned}|], mempty, mempty)
-- avoid nestes hamlet $maybe with duplicated $nothing -- avoid nestes hamlet $maybe with duplicated $nothing
getCorrSheetStatus :: Maybe UserId -> SheetName -> Maybe CorrectionInfo getCorrSheetStatus :: Maybe UserId -> SheetName -> Maybe CorrectionInfo

View File

@ -79,7 +79,7 @@ makeSubmissionForm cid shid mASDefinition msmid uploadMode grouping mPrev isLect
| otherwise -> MsgEmailInvitationWarningPrevCoSubmittors | otherwise -> MsgEmailInvitationWarningPrevCoSubmittors
$(widgetFile "widgets/massinput/submissionUsers/cellInvitation") $(widgetFile "widgets/massinput/submissionUsers/cellInvitation")
miCell' csrf (Right uid) = do miCell' csrf (Right uid) = do
(User{..}, hasSubmitted) <- liftHandler . runDB $ do (usr, hasSubmitted) <- liftHandler . runDB $ do
user <- getJust uid user <- getJust uid
hasSubmitted <- E.selectExists . E.from $ \(submissionUser `E.InnerJoin` submission) -> do hasSubmitted <- E.selectExists . E.from $ \(submissionUser `E.InnerJoin` submission) -> do
E.on $ submissionUser E.^. SubmissionUserSubmission E.==. submission E.^. SubmissionId E.on $ submissionUser E.^. SubmissionUserSubmission E.==. submission E.^. SubmissionId

View File

@ -63,7 +63,7 @@ tutorialForm cid template html = do
invWarnMsg <- messageIconI Info IconEmail MsgEmailInvitationWarning invWarnMsg <- messageIconI Info IconEmail MsgEmailInvitationWarning
$(widgetFile "tutorial/tutorMassInput/cellInvitation") $(widgetFile "tutorial/tutorMassInput/cellInvitation")
miCell' (Right userId) = do miCell' (Right userId) = do
User{..} <- liftHandler . runDB $ get404 userId usr <- liftHandler . runDB $ get404 userId
$(widgetFile "tutorial/tutorMassInput/cellKnown") $(widgetFile "tutorial/tutorMassInput/cellKnown")
miLayout' :: MassInputLayout ListLength (Either UserEmail UserId) () miLayout' :: MassInputLayout ListLength (Either UserEmail UserId) ()

View File

@ -589,7 +589,7 @@ postAdminUserR uuid = do
formResult systemFunctionsResult userSystemFunctionsAction formResult systemFunctionsResult userSystemFunctionsAction
formResult assimilateFormResult assimilateAction formResult assimilateFormResult assimilateAction
let heading = let heading =
[whamlet|_{MsgAdminUserHeadingFor} ^{nameEmailWidget userEmail userDisplayName userSurname}|] [whamlet|_{MsgAdminUserHeadingFor} ^{userEmailWidget user}|]
-- Delete Button needed in data-delete -- Delete Button needed in data-delete
(deleteWgt, deleteEnctype) <- generateFormPost (identifyForm FIDUserDelete buttonForm :: Form ButtonDelete) (deleteWgt, deleteEnctype) <- generateFormPost (identifyForm FIDUserDelete buttonForm :: Form ButtonDelete)
let deleteForm = wrapForm deleteWgt def let deleteForm = wrapForm deleteWgt def
@ -666,7 +666,7 @@ getUserPasswordR, postUserPasswordR :: CryptoUUIDUser -> Handler Html
getUserPasswordR = postUserPasswordR getUserPasswordR = postUserPasswordR
postUserPasswordR cID = do postUserPasswordR cID = do
tUid <- decrypt cID tUid <- decrypt cID
User{..} <- runDB $ get404 tUid usr@User{..} <- runDB $ get404 tUid
PWHashConf{..} <- getsYesod $ view _appAuthPWHash PWHashConf{..} <- getsYesod $ view _appAuthPWHash
isModal <- hasCustomHeader HeaderIsModal isModal <- hasCustomHeader HeaderIsModal
@ -704,7 +704,7 @@ postUserPasswordR cID = do
liftHandler . runDB $ update tUid [ UserAuthentication =. AuthPWHash newHash ] liftHandler . runDB $ update tUid [ UserAuthentication =. AuthPWHash newHash ]
tell . pure =<< messageI Success MsgPasswordChangedSuccess tell . pure =<< messageI Success MsgPasswordChangedSuccess
siteLayout [whamlet|_{MsgUserPasswordHeadingFor} ^{nameEmailWidget userEmail userDisplayName userSurname}|] $ siteLayout [whamlet|_{MsgUserPasswordHeadingFor} ^{userEmailWidget usr}|] $
wrapForm passFormWidget def wrapForm passFormWidget def
{ formAction = Just . SomeRoute $ UserPasswordR cID { formAction = Just . SomeRoute $ UserPasswordR cID
, formEncoding = passEnctype , formEncoding = passEnctype

View File

@ -393,29 +393,28 @@ upsertAvsUserById api = do
case (mbuid, mbapd) of case (mbuid, mbapd) of
( _ , Nothing ) -> throwM $ AvsUserUnknownByAvs api -- User not found in AVS at all, i.e. no valid card exists yet ( _ , Nothing ) -> throwM $ AvsUserUnknownByAvs api -- User not found in AVS at all, i.e. no valid card exists yet
(Nothing, Just AvsDataPerson{avsPersonFirstName= Text.strip -> avsFirstName, avsPersonLastName= Text.strip -> avsSurname, ..}) -> do -- No LDAP User, but found in AVS; create new user (Nothing, Just AvsDataPerson{avsPersonFirstName= Text.strip -> avsFirstName, avsPersonLastName= Text.strip -> avsSurname, ..}) -> do -- No LDAP User, but found in AVS; create new user
let firmAddress = guessLicenceAddress avsPersonPersonCards let (mbCompany, mbCoFirmAddr, _) = guessLicenceAddress avsPersonPersonCards
mbCompany = firmAddress ^? _Just . _1 . _Just userFirmAddr= plaintextToStoredMarkup <$> mbCoFirmAddr
userFirmAddr= plaintextToStoredMarkup . mergeCompanyAddress <$> firmAddress
pinCard = Set.lookupMax avsPersonPersonCards pinCard = Set.lookupMax avsPersonPersonCards
userPin = personCard2pin <$> pinCard userPin = personCard2pin <$> pinCard
fakeIdent = CI.mk $ "AVSID:" <> tshow api fakeIdent = CI.mk $ "AVSID:" <> tshow api
fakeNo = CI.mk $ "AVSNO:" <> tshow avsPersonPersonNo fakeNo = CI.mk $ "AVSNO:" <> tshow avsPersonPersonNo
newUsr = AddUserData newUsr = AddUserData
{ audTitle = Nothing { audTitle = Nothing
, audFirstName = avsFirstName , audFirstName = avsFirstName
, audSurname = avsSurname , audSurname = avsSurname
, audDisplayName = avsFirstName <> Text.cons ' ' avsSurname , audDisplayName = avsFirstName <> Text.cons ' ' avsSurname
, audDisplayEmail = "" -- Email is unknown in this version of the avs query, to be updated later (FUTURE TODO) , audDisplayEmail = "" -- Email is unknown in this version of the avs query, to be updated later (FUTURE TODO)
, audMatriculation = Nothing , audMatriculation = Nothing
, audSex = Nothing , audSex = Nothing
, audBirthday = Nothing , audBirthday = Nothing
, audMobile = Nothing , audMobile = Nothing
, audTelephone = Nothing , audTelephone = Nothing
, audFPersonalNumber = avsInternalPersonalNo <$> canonical avsPersonInternalPersonalNo , audFPersonalNumber = avsInternalPersonalNo <$> canonical avsPersonInternalPersonalNo
, audFDepartment = Nothing , audFDepartment = Nothing
, audPostAddress = userFirmAddr , audPostAddress = userFirmAddr
, audPrefersPostal = True , audPrefersPostal = True
, audPinPassword = userPin , audPinPassword = userPin
, audEmail = fakeNo -- Email is unknown in this version of the avs query, to be updated later (FUTURE TODO) , audEmail = fakeNo -- Email is unknown in this version of the avs query, to be updated later (FUTURE TODO)
, audIdent = fakeIdent -- use AvsPersonId instead , audIdent = fakeIdent -- use AvsPersonId instead
, audAuth = maybe AuthKindNoLogin (const AuthKindLDAP) avsPersonInternalPersonalNo -- FUTURE TODO: if email is known, use AuthKinfPWHash for email invite, if no internal personnel number is known , audAuth = maybe AuthKindNoLogin (const AuthKindLDAP) avsPersonInternalPersonalNo -- FUTURE TODO: if email is known, use AuthKinfPWHash for email invite, if no internal personnel number is known
@ -424,24 +423,22 @@ upsertAvsUserById api = do
whenIsJust mbUid $ \uid -> runDB $ do whenIsJust mbUid $ \uid -> runDB $ do
now <- liftIO getCurrentTime now <- liftIO getCurrentTime
insert_ $ UserAvs avsPersonPersonID uid avsPersonPersonNo insert_ $ UserAvs avsPersonPersonID uid avsPersonPersonNo
forM_ avsPersonPersonCards $ -- save all cards for later forM_ avsPersonPersonCards $ -- save all cards for later comparisons whether an update occurred
-- let cs :: Set AvsDataPersonCard = Set.fromList $ catMaybes [pinCard, addrCard] -- let cs :: Set AvsDataPersonCard = Set.fromList $ catMaybes [pinCard, addrCard]
-- forM_ cs $ -- only save used cards for the postal address update detection -- forM_ cs $ -- only save used cards for the postal address update detection
\avsCard -> insert_ $ UserAvsCard avsPersonPersonID (getFullCardNo avsCard) avsCard now \avsCard -> insert_ $ UserAvsCard avsPersonPersonID (getFullCardNo avsCard) avsCard now
upsertUserCompany uid mbCompany upsertUserCompany uid mbCompany userFirmAddr
return mbUid return mbUid
(Just (Entity _ UserAvs{userAvsUser=uid}), Just AvsDataPerson{avsPersonPersonCards}) -> do -- known user, update address and pinPassword (Just (Entity _ UserAvs{userAvsUser=uid}), Just AvsDataPerson{avsPersonPersonCards}) -> do -- known user, update address and pinPassword
let firmAddress = guessLicenceAddress avsPersonPersonCards let (mbCompany, mbCoFirmAddr, _) = guessLicenceAddress avsPersonPersonCards
mbCompany = firmAddress ^? _Just . _1 . _Just
mbCoFirmAddr= mergeCompanyAddress <$> firmAddress
userFirmAddr= plaintextToStoredMarkup <$> mbCoFirmAddr userFirmAddr= plaintextToStoredMarkup <$> mbCoFirmAddr
pinCard = Set.lookupMax avsPersonPersonCards pinCard = Set.lookupMax avsPersonPersonCards
userPin = personCard2pin <$> pinCard userPin = personCard2pin <$> pinCard
runDB $ do runDB $ do
now <- liftIO getCurrentTime now <- liftIO getCurrentTime
oldCards <- selectList [UserAvsCardPersonId ==. api] [] oldCards <- selectList [UserAvsCardPersonId ==. api] []
let oldAddrs = Set.fromList $ mapMaybe (maybeCompanyAddress . userAvsCardCard . entityVal) oldCards let oldAddrs = Set.fromList $ mapMaybe (snd3 . getCompanyAddress . userAvsCardCard . entityVal) oldCards
unless (maybe True (`Set.member` oldAddrs) mbCoFirmAddr) $ do -- update postal address, unless the exact address had been seen before unless (maybe True (`Set.member` oldAddrs) mbCoFirmAddr) $ do -- update postal address, unless the exact address had been seen before
encRecipient :: CryptoUUIDUser <- encrypt uid encRecipient :: CryptoUUIDUser <- encrypt uid
$logInfoS "AVS" $ "Postal address updated for" <> tshow encRecipient $logInfoS "AVS" $ "Postal address updated for" <> tshow encRecipient
@ -452,7 +449,7 @@ upsertAvsUserById api = do
updateWhere [UserId ==. uid, UserPinPassword !=. userPin, UserPinPassword <-. Nothing:oldPins] updateWhere [UserId ==. uid, UserPinPassword !=. userPin, UserPinPassword <-. Nothing:oldPins]
[UserPinPassword =. userPin] [UserPinPassword =. userPin]
insert_ $ UserAvsCard api (getFullCardNo pCard) pCard now insert_ $ UserAvsCard api (getFullCardNo pCard) pCard now
upsertUserCompany uid mbCompany upsertUserCompany uid mbCompany userFirmAddr
forM_ avsPersonPersonCards $ \aCard -> void $ upsert UserAvsCard forM_ avsPersonPersonCards $ \aCard -> void $ upsert UserAvsCard
{ userAvsCardPersonId = api { userAvsCardPersonId = api
, userAvsCardCardNo = getFullCardNo aCard , userAvsCardCardNo = getFullCardNo aCard
@ -491,7 +488,7 @@ lookupAvsUsers apis = do
-- | Like `Handler.Utils.getReceivers`, but calls upsertAvsUserById on each user to ensure that postal address is up-to-date -- | Like `Handler.Utils.getReceivers`, but calls upsertAvsUserById on each user to ensure that postal address is up-to-date
updateReceivers :: UserId -> Handler (Entity User, [Entity User], Bool) updateReceivers :: UserId -> Handler (Entity User, [Entity User], Bool)
updateReceivers uid = do updateReceivers uid = do
(underling :: Entity User, avsUnderling :: Maybe (Entity UserAvs), avsSupers :: [(Entity UserSupervisor, Maybe (Entity UserAvs))]) <- runDB $ (,,) (underling :: Entity User, avsUnderling :: Maybe (Entity UserAvs), avsSupers :: [(E.Value UserId, E.Value (Maybe AvsPersonId))]) <- runDB $ (,,)
<$> getJustEntity uid <$> getJustEntity uid
<*> getBy (UniqueUserAvsUser uid) <*> getBy (UniqueUserAvsUser uid)
<*> (E.select $ do <*> (E.select $ do
@ -501,11 +498,12 @@ updateReceivers uid = do
`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)
E.&&. (usrSuper E.^. UserSupervisorRerouteNotifications) E.&&. (usrSuper E.^. UserSupervisorRerouteNotifications)
pure (usrSuper, usrAvs) pure (usrSuper E.^. UserSupervisorSupervisor, usrAvs E.?. UserAvsPersonId)
) )
let (superVs, avsIds) = unzip avsSupers let (superVs, avsIds) = unzip avsSupers
toUpdate = Set.fromList . fmap (userAvsPersonId . entityVal) $ catMaybes (avsUnderling : avsIds) receiverIDs :: [UserId] = E.unValue <$> superVs
receiverIDs :: [UserId] = userSupervisorSupervisor . entityVal <$> superVs underlingAvsId = userAvsPersonId . entityVal <$> avsUnderling
toUpdate = Set.fromList $ catMaybes (underlingAvsId : (E.unValue <$> avsIds))
directResult = return (underling, pure underling, True) directResult = return (underling, pure underling, True)
forM_ toUpdate (void . maybeCatchAll . upsertAvsUserById) -- attempt to update postaddress from AVS forM_ toUpdate (void . maybeCatchAll . upsertAvsUserById) -- attempt to update postaddress from AVS
if null receiverIDs if null receiverIDs

View File

@ -15,9 +15,9 @@ import qualified Data.Text as Text
import Database.Persist.Postgresql import Database.Persist.Postgresql
-- | Ensure that the given user is linked to the given company -- | Ensure that the given user is linked to the given company
upsertUserCompany :: UserId -> Maybe Text -> DB () upsertUserCompany :: UserId -> Maybe Text -> Maybe StoredMarkup -> DB ()
upsertUserCompany uid (Just cName) | notNull cName = do upsertUserCompany uid (Just cName) cAddr | notNull cName = do
cid <- upsertCompany cName cid <- upsertCompany cName cAddr
void $ upsertBy (UniqueUserCompany uid cid) void $ upsertBy (UniqueUserCompany uid cid)
(UserCompany uid cid False False) (UserCompany uid cid False False)
[] []
@ -25,12 +25,13 @@ upsertUserCompany uid (Just cName) | notNull cName = do
upsertManyWhere [ UserSupervisor super uid reroute upsertManyWhere [ UserSupervisor super uid reroute
| Entity{entityVal=UserCompany{userCompanyUser=super, userCompanySupervisorReroute=reroute, userCompanySupervisor=True}} <- superVs | Entity{entityVal=UserCompany{userCompanyUser=super, userCompanySupervisorReroute=reroute, userCompanySupervisor=True}} <- superVs
] [] [] [] ] [] [] []
upsertUserCompany uid _ = upsertUserCompany uid _ _ =
deleteWhere [ UserCompanyUser ==. uid ] -- maybe also delete company supervisors? deleteWhere [ UserCompanyUser ==. uid ] -- maybe also delete company supervisors?
-- | Does not update company address for now
upsertCompany :: Text -> DB CompanyId -- TODO: update company address, maybe?!
upsertCompany cName = upsertCompany :: Text -> Maybe StoredMarkup -> DB CompanyId
upsertCompany cName cAddr =
let cName' = CI.mk cName in let cName' = CI.mk cName in
getBy (UniqueCompanyName cName') >>= \case getBy (UniqueCompanyName cName') >>= \case
Just ent -> return $ entityKey ent Just ent -> return $ entityKey ent
@ -39,7 +40,7 @@ upsertCompany cName =
Nothing -> do Nothing -> do
let cShort = companyShorthandFromName cName let cShort = companyShorthandFromName cName
cShort' <- findShort cName' $ CI.mk cShort cShort' <- findShort cName' $ CI.mk cShort
let compy = Company cName' cShort' 0 False Nothing -- TODO let compy = Company cName' cShort' 0 False cAddr -- TODO: Fix this once AVS CR3 SCF-165 is implemented
either entityKey id <$> insertBy compy either entityKey id <$> insertBy compy
where where
findShort :: CompanyName -> CompanyShorthand -> DB CompanyShorthand findShort :: CompanyName -> CompanyShorthand -> DB CompanyShorthand

View File

@ -16,6 +16,7 @@ import Handler.Utils.Pandoc
import Handler.Utils.Files import Handler.Utils.Files
import Handler.Utils.Widgets (nameHtml') -- TODO: how to use name widget here? import Handler.Utils.Widgets (nameHtml') -- TODO: how to use name widget here?
import Handler.Utils.Users (getReceivers) import Handler.Utils.Users (getReceivers)
import Handler.Utils.Profile (pickValidEmail)
import qualified Data.CaseInsensitive as CI import qualified Data.CaseInsensitive as CI
@ -34,8 +35,8 @@ addRecipientsDB :: ( MonadMail m
-- ^ @setRecipientId uid@ throws an exception if @uid@ does not refer to an existing user -- ^ @setRecipientId uid@ throws an exception if @uid@ does not refer to an existing user
addRecipientsDB uFilter = runConduit $ transPipe (liftHandler . runDB) (selectSource uFilter [Asc UserDisplayName]) .| C.mapM_ addRecipient addRecipientsDB uFilter = runConduit $ transPipe (liftHandler . runDB) (selectSource uFilter [Asc UserDisplayName]) .| C.mapM_ addRecipient
where where
addRecipient (Entity _ User{userEmail, userDisplayName}) = do addRecipient (Entity _ User{userEmail, userDisplayEmail, userDisplayName}) = do
let addr = Address (Just userDisplayName) $ CI.original userEmail let addr = Address (Just userDisplayName) $ CI.original $ pickValidEmail userDisplayEmail userEmail
_mailTo %= flip snoc addr _mailTo %= flip snoc addr
userAddressFrom :: User -> Address userAddressFrom :: User -> Address
@ -47,9 +48,9 @@ userAddressFrom User{userDisplayEmail, userDisplayName} = Address (Just userDisp
userAddress :: User -> Address userAddress :: User -> Address
-- ^ Format an e-mail address suitable for usage as a recipient -- ^ Format an e-mail address suitable for usage as a recipient
-- --
-- Uses `userEmail` -- Like userAddressFrom and no longer uses `userEmail`, since unlike Uni2work, userEmail from LDAP is untrustworthy.
userAddress User{userEmail, userDisplayName} = Address (Just userDisplayName) $ CI.original userEmail userAddress User{userEmail, userDisplayEmail, userDisplayName}
= Address (Just userDisplayName) $ CI.original $ pickValidEmail userDisplayEmail userEmail
-- | Send an email to the given UserId or to all registered Supervisor with rerouteNotifications == True -- | Send an email to the given UserId or to all registered Supervisor with rerouteNotifications == True
userMailT :: ( MonadHandler m userMailT :: ( MonadHandler m
@ -60,7 +61,7 @@ userMailT :: ( MonadHandler m
userMailT uid mAct = do userMailT uid mAct = do
(underling, receivers, undercopy) <- liftHandler . runDB $ getReceivers uid (underling, receivers, undercopy) <- liftHandler . runDB $ getReceivers uid
let undername = underling ^. _userDisplayName -- nameHtml' underling let undername = underling ^. _userDisplayName -- nameHtml' underling
undermail = CI.original $ underling ^. _userEmail undermail = CI.original $ pickValidEmail (underling ^. _userDisplayEmail) (underling ^. _userEmail)
infoSupervised :: Hamlet.HtmlUrlI18n UniWorXSendMessage (Route UniWorX) = [ihamlet| infoSupervised :: Hamlet.HtmlUrlI18n UniWorXSendMessage (Route UniWorX) = [ihamlet|
<h2>_{MsgMailSupervisedNote} <h2>_{MsgMailSupervisedNote}
<p> <p>

View File

@ -9,7 +9,7 @@ module Handler.Utils.Profile
, validDisplayName , validDisplayName
, fixDisplayName , fixDisplayName
, validPostAddress , validPostAddress
, validEmail, validEmail' , validEmail, validEmail', pickValidEmail
) where ) where
import Import.NoFoundation import Import.NoFoundation
@ -84,3 +84,9 @@ validEmail = Email.isValid . encodeUtf8
validEmail' :: UserEmail -> Bool -- UserEmail = CI Text validEmail' :: UserEmail -> Bool -- UserEmail = CI Text
validEmail' = Email.isValid . encodeUtf8 . CI.original validEmail' = Email.isValid . encodeUtf8 . CI.original
-- | returns first argument, if it is a valid email address; returns second argument untested otherwise; convenience function
pickValidEmail :: UserEmail -> UserEmail -> UserEmail
pickValidEmail x y
| validEmail' x = x
| otherwise = y

View File

@ -207,7 +207,7 @@ cellHasMatrikelnummer :: (IsDBTable m a, HasUser u) => u -> DBCell m a
cellHasMatrikelnummer = maybe mempty textCell . view _userMatrikelnummer cellHasMatrikelnummer = maybe mempty textCell . view _userMatrikelnummer
cellHasEMail :: (IsDBTable m a, HasUser u) => u -> DBCell m a cellHasEMail :: (IsDBTable m a, HasUser u) => u -> DBCell m a
cellHasEMail = emailCell . view _userEmail cellHasEMail = emailCell . view _userDisplayEmail
cellHasSemester :: (IsDBTable m c, HasStudyFeatures a) => a -> DBCell m c cellHasSemester :: (IsDBTable m c, HasStudyFeatures a) => a -> DBCell m c

View File

@ -398,7 +398,7 @@ fltrUserNameEmail :: (IsFilterColumn t (a -> Set Text -> E.SqlExpr (E.Value Bool
fltrUserNameEmail queryUser = ( "user-name-email", FilterColumn $ anyFilter fltrUserNameEmail queryUser = ( "user-name-email", FilterColumn $ anyFilter
[ mkContainsFilter $ queryUser >>> (E.^. UserDisplayName) [ mkContainsFilter $ queryUser >>> (E.^. UserDisplayName)
, mkContainsFilter $ queryUser >>> (E.^. UserSurname) , mkContainsFilter $ queryUser >>> (E.^. UserSurname)
, mkContainsFilterWith CI.mk $ queryUser >>> (E.^. UserEmail) , mkContainsFilterWith CI.mk $ queryUser >>> (E.^. UserDisplayEmail)
] ]
) )
@ -463,14 +463,14 @@ colUserEmail :: (IsDBTable m c, HasUser a) => Colonnade Sortable a (DBCell m c)
colUserEmail = sortable (Just "user-email") (i18nCell MsgTableEmail) cellHasEMail colUserEmail = sortable (Just "user-email") (i18nCell MsgTableEmail) cellHasEMail
sortUserEmail :: IsString d => (t -> E.SqlExpr (Entity User)) -> (d, SortColumn t r') sortUserEmail :: IsString d => (t -> E.SqlExpr (Entity User)) -> (d, SortColumn t r')
sortUserEmail queryUser = ( "user-email", SortColumn $ queryUser >>> (E.^. UserEmail)) sortUserEmail queryUser = ( "user-email", SortColumn $ queryUser >>> (E.^. UserDisplayEmail))
fltrUserEmail :: ( IsFilterColumn t (a -> Set (CI Text) -> E.SqlExpr (E.Value Bool)) fltrUserEmail :: ( IsFilterColumn t (a -> Set (CI Text) -> E.SqlExpr (E.Value Bool))
, IsString d , IsString d
) )
=> (a -> E.SqlExpr (Entity User)) => (a -> E.SqlExpr (Entity User))
-> (d, FilterColumn t fs) -> (d, FilterColumn t fs)
fltrUserEmail queryUser = ("user-email", FilterColumn . mkContainsFilter $ queryUser >>> (E.^. UserEmail)) fltrUserEmail queryUser = ("user-email", FilterColumn . mkContainsFilter $ queryUser >>> (E.^. UserDisplayEmail))
fltrUserEmailUI :: Maybe (Map FilterKey [Text]) -> AForm (YesodDB UniWorX) (Map FilterKey [Text]) fltrUserEmailUI :: Maybe (Map FilterKey [Text]) -> AForm (YesodDB UniWorX) (Map FilterKey [Text])
fltrUserEmailUI mPrev = fltrUserEmailUI mPrev =

View File

@ -64,6 +64,9 @@ linkUserWidget lnk (Entity uid usr) = do
uuid <- encrypt uid uuid <- encrypt uid
simpleLink (userWidget usr) (lnk uuid) simpleLink (userWidget usr) (lnk uuid)
userEmailWidget :: HasUser c => c -> Widget
userEmailWidget x = nameEmailWidget (x ^. _userDisplayEmail) (x ^. _userDisplayName) (x ^. _userSurname)
-- | toWidget-Version of @nameEmailHtml@, for convenience -- | toWidget-Version of @nameEmailHtml@, for convenience
nameEmailWidget :: UserEmail -- ^ userEmail nameEmailWidget :: UserEmail -- ^ userEmail
-> Text -- ^ userDisplayName -> Text -- ^ userDisplayName

View File

@ -101,30 +101,23 @@ getValidLicence cutoff licence' cards = Set.lookupMax validLicenceCards
avsDataValid && (avsDataValidTo >= cutoff) && (licence `Set.member` avsDataCardAreas) avsDataValid && (avsDataValidTo >= cutoff) && (licence `Set.member` avsDataCardAreas)
getCompanyAddress :: AvsDataPersonCard -> Maybe (Maybe Text, Text, AvsDataPersonCard) getCompanyAddress :: AvsDataPersonCard -> (Maybe Text, Maybe Text, Maybe AvsDataPersonCard)
getCompanyAddress card@AvsDataPersonCard{..} getCompanyAddress card@AvsDataPersonCard{..}
| Just street <- avsDataStreet | Just street <- avsDataStreet
, Just pcode <- avsDataPostalCode , Just pcode <- avsDataPostalCode
, Just city <- avsDataCity , Just city <- avsDataCity
= Just (avsDataFirm, Text.unlines [street, Text.unwords [pcode, city]], card) = (avsDataFirm, Just $ Text.unlines $ mcons avsDataFirm [street, Text.unwords [pcode, city]], Just card)
| otherwise = Nothing | isJust avsDataFirm = (avsDataFirm, Nothing, Just card)
| otherwise = (Nothing, Nothing, Nothing)
-- | From a set of card, choose the one with the most complete postal address. -- | From a set of card, choose the one with the most complete postal address.
-- Returns company, postal address and the associated card where the address was taken from -- Returns company, postal address and the associated card where the address was taken from
guessLicenceAddress :: Set AvsDataPersonCard -> Maybe (Maybe Text, Text, AvsDataPersonCard) guessLicenceAddress :: Set AvsDataPersonCard -> (Maybe Text, Maybe Text, Maybe AvsDataPersonCard)
guessLicenceAddress cards guessLicenceAddress cards
| Just c <- Set.lookupMax cards | Just c <- Set.lookupMax cards
, card <- Set.foldr pickLicenceAddress c cards , card <- Set.foldr pickLicenceAddress c cards
= getCompanyAddress card = getCompanyAddress card
| otherwise = Nothing | otherwise = (Nothing, Nothing, Nothing)
-- | Helper for guessLicenceAddress or getCompanyAddress
mergeCompanyAddress :: (Maybe Text, Text, a) -> Text
mergeCompanyAddress (Nothing , addr, _) = addr
mergeCompanyAddress (Just firm, addr, _) = firm <> Text.cons '\n' addr
maybeCompanyAddress :: AvsDataPersonCard -> Maybe Text
maybeCompanyAddress = fmap mergeCompanyAddress . getCompanyAddress
hasAddress :: AvsDataPersonCard -> Bool hasAddress :: AvsDataPersonCard -> Bool
hasAddress AvsDataPersonCard{..} = isJust avsDataStreet && isJust avsDataCity && isJust avsDataPostalCode hasAddress AvsDataPersonCard{..} = isJust avsDataStreet && isJust avsDataCity && isJust avsDataPostalCode

View File

@ -9,10 +9,10 @@ $# SPDX-License-Identifier: AGPL-3.0-or-later
<tr .table__row> <tr .table__row>
<th .table__th>_{MsgTableSubmission} <th .table__th>_{MsgTableSubmission}
<td .table__td>#{cid} <td .table__td>#{cid}
$maybe Entity _ User{userDisplayName, userSurname, userEmail} <- corrector $maybe Entity _ usr <- corrector
<tr .table__row> <tr .table__row>
<th .table__th>_{MsgRatingBy} <th .table__th>_{MsgRatingBy}
<td .table__td>^{nameEmailWidget userEmail userDisplayName userSurname} <td .table__td>^{userEmailWidget usr}
$maybe time <- submissionRatingTime $maybe time <- submissionRatingTime
<tr .table__row> <tr .table__row>
<th .table__th>_{MsgTableRatingTime} <th .table__th>_{MsgTableRatingTime}

View File

@ -6,6 +6,6 @@ $# SPDX-License-Identifier: AGPL-3.0-or-later
<td colspan=2> <td colspan=2>
#{csrf} #{csrf}
^{nameEmailWidget userEmail userDisplayName userSurname} # ^{userEmailWidget usr} #
<td> <td>
^{fvWidget lrwView} ^{fvWidget lrwView}

View File

@ -24,7 +24,7 @@ $# SPDX-License-Identifier: AGPL-3.0-or-later
<dt .deflist__dt>_{MsgTableSex} <dt .deflist__dt>_{MsgTableSex}
<dd .deflist__dd>_{sex} <dd .deflist__dd>_{sex}
<dt .deflist__dt>_{MsgTableEmail} <dt .deflist__dt>_{MsgTableEmail}
<dd .deflist__dd>#{mailtoHtml userEmail} <dd .deflist__dd>#{mailtoHtml (pickValidEmail userDisplayEmail userEmail)}
$maybe date <- mRegAt $maybe date <- mRegAt
<dt .deflist__dt>_{MsgRegisteredSince} <dt .deflist__dt>_{MsgRegisteredSince}
<dd .deflist__dd>#{date} <dd .deflist__dd>#{date}

View File

@ -52,9 +52,9 @@ $maybe ExternalExamResult{externalExamResultResult} <- mResult
<ul> <ul>
$forall s <- staff $forall s <- staff
$case s $case s
$of Right (Entity _ User{userDisplayName, userDisplayEmail, userSurname}) $of Right (Entity _ usr)
<li> <li>
^{nameEmailWidget userDisplayEmail userDisplayName userSurname} ^{userEmailWidget usr}
$of Left email $of Left email
<li .email> <li .email>
#{email} #{email}

View File

@ -5,4 +5,4 @@ $#
$# SPDX-License-Identifier: AGPL-3.0-or-later $# SPDX-License-Identifier: AGPL-3.0-or-later
<td colspan=2> <td colspan=2>
^{nameEmailWidget userEmail userDisplayName userSurname} ^{userEmailWidget usr}

View File

@ -6,7 +6,7 @@ $# SPDX-License-Identifier: AGPL-3.0-or-later
<h2> <h2>
Sind Sie sich absolut sicher Sind Sie sich absolut sicher
Benutzer:in ^{nameEmailWidget userEmail userDisplayName userSurname} zu löschen? Benutzer:in ^{userEmailWidget user} zu löschen?
<p> <p>
Während der Testphase von Uni2work Während der Testphase von Uni2work
werden Benutzer:innen hiermit vollständig aus der Live-Datenbank mit werden Benutzer:innen hiermit vollständig aus der Live-Datenbank mit

View File

@ -5,7 +5,7 @@ $#
$# SPDX-License-Identifier: AGPL-3.0-or-later $# SPDX-License-Identifier: AGPL-3.0-or-later
<h2> <h2>
Are you sure that you want to permanently delete ^{nameEmailWidget userEmail userDisplayName userSurname}? Are you sure that you want to permanently delete ^{userEmailWidget user}?
<p> <p>
During the testing phase users are deleted wholly from the live database via During the testing phase users are deleted wholly from the live database via
<code>DELETE CASCADE uid <code>DELETE CASCADE uid

View File

@ -54,14 +54,14 @@ $# SPDX-License-Identifier: AGPL-3.0-or-later
<dd .deflist__dd> <dd .deflist__dd>
^{formatTimeW SelFormatDateTime postUpdate} ^{formatTimeW SelFormatDateTime postUpdate}
<dt .deflist__dt> <dt .deflist__dt>
_{MsgTableEmail} _{MsgUserDisplayEmail}
<dd .deflist__dd> <dd .deflist__dd .email>
#{mailtoHtml userEmail} #{userDisplayEmail}
$if userEmail /= userDisplayEmail $if userEmail /= userDisplayEmail
<dt .deflist__dt> <dt .deflist__dt>
_{MsgUserDisplayEmail} _{MsgUserSystemEmail}
<dd .deflist__dd .email> <dd .deflist__dd>
#{userDisplayEmail} #{mailtoHtml userEmail}
<dt .deflist__dt> <dt .deflist__dt>
_{MsgAdminUserPinPassword} _{MsgAdminUserPinPassword}
<dd .deflist__dd> <dd .deflist__dd>

View File

@ -12,7 +12,7 @@ $# SPDX-License-Identifier: AGPL-3.0-or-later
<dt .deflist__dt>_{MsgTableTutorialTutors} <dt .deflist__dt>_{MsgTableTutorialTutors}
<dd .deflist__dd> <dd .deflist__dd>
<ul> <ul>
$forall (Entity _ User{userDisplayName, userDisplayEmail, userSurname}) <- tutors $forall (Entity _ usr) <- tutors
<li> <li>
^{nameEmailWidget userDisplayEmail userDisplayName userSurname} ^{userEmailWidget usr}
^{participantTable} ^{participantTable}

View File

@ -5,4 +5,4 @@ $#
$# SPDX-License-Identifier: AGPL-3.0-or-later $# SPDX-License-Identifier: AGPL-3.0-or-later
<td colspan=2> <td colspan=2>
^{nameEmailWidget userEmail userDisplayName userSurname} ^{userEmailWidget usr}

View File

@ -5,4 +5,4 @@ $#
$# SPDX-License-Identifier: AGPL-3.0-or-later $# SPDX-License-Identifier: AGPL-3.0-or-later
<td colspan=2> <td colspan=2>
^{nameEmailWidget userEmail userDisplayName userSurname} ^{userEmailWidget usr}

View File

@ -5,4 +5,4 @@ $#
$# SPDX-License-Identifier: AGPL-3.0-or-later $# SPDX-License-Identifier: AGPL-3.0-or-later
<td colspan=2> <td colspan=2>
^{nameEmailWidget userEmail userDisplayName userSurname} ^{userEmailWidget usr}

View File

@ -7,10 +7,10 @@ $# SPDX-License-Identifier: AGPL-3.0-or-later
$maybe wrn <- knownWarning $maybe wrn <- knownWarning
<td> <td>
#{csrf} #{csrf}
^{nameEmailWidget userEmail userDisplayName userSurname} ^{userEmailWidget usr}
<td .table__td--tooltip> <td .table__td--tooltip>
^{messageTooltip wrn} ^{messageTooltip wrn}
$nothing $nothing
<td colspan=2> <td colspan=2>
#{csrf} #{csrf}
^{nameEmailWidget userEmail userDisplayName userSurname} ^{userEmailWidget usr}