feat(invitations): anonymous invitations

This commit is contained in:
Gregor Kleen 2020-07-15 09:31:36 +02:00
parent 9a2cba5c0a
commit 1380d9d21e
10 changed files with 36 additions and 17 deletions

View File

@ -35,7 +35,7 @@ bearer-expiration: 604800
bearer-encoding: HS256 bearer-encoding: HS256
maximum-content-length: "_env:MAX_UPLOAD_SIZE:134217728" maximum-content-length: "_env:MAX_UPLOAD_SIZE:134217728"
session-files-expire: 3600 session-files-expire: 3600
prune-unreferenced-files: 86400 prune-unreferenced-files: 600
health-check-interval: health-check-interval:
matching-cluster-config: "_env:HEALTHCHECK_INTERVAL_MATCHING_CLUSTER_CONFIG:600" matching-cluster-config: "_env:HEALTHCHECK_INTERVAL_MATCHING_CLUSTER_CONFIG:600"
http-reachable: "_env:HEALTHCHECK_INTERVAL_HTTP_REACHABLE:600" http-reachable: "_env:HEALTHCHECK_INTERVAL_HTTP_REACHABLE:600"
@ -156,7 +156,7 @@ upload-cache:
auto-discover-region: "_env:UPLOAD_S3_AUTO_DISCOVER_REGION:true" auto-discover-region: "_env:UPLOAD_S3_AUTO_DISCOVER_REGION:true"
disable-cert-validation: "_env:UPLOAD_S3_DISABLE_CERT_VALIDATION:false" disable-cert-validation: "_env:UPLOAD_S3_DISABLE_CERT_VALIDATION:false"
upload-cache-bucket: "uni2work-uploads" upload-cache-bucket: "uni2work-uploads"
inject-files: 300 inject-files: 60
server-sessions: server-sessions:
idle-timeout: 28807 idle-timeout: 28807
@ -220,10 +220,10 @@ favourites-quick-actions-cache-ttl: 120 # s
token-buckets: token-buckets:
inject-files: inject-files:
depth: 2097152 # 2MiB depth: 62914560 # 60MiB
inv-rate: 9.5e-7 # 1MiB/s inv-rate: 9.5e-7 # 1MiB/s
initial-value: 0 initial-value: 0
prune-files: prune-files:
depth: 10485760 # 10MiB depth: 1258291200 # 1200MiB
inv-rate: 1.9e-6 # 2MiB/s inv-rate: 1.9e-6 # 2MiB/s
initial-value: 0 initial-value: 0

View File

@ -297,6 +297,7 @@ runSimulation' LoadSheetSubmission = do
name <- Scalpel.attr "name" fileSel name <- Scalpel.attr "name" fileSel
return $ partFileRequestBody (decodeUtf8 $ toStrict name) "loadtest.bin" fileUploadPart return $ partFileRequestBody (decodeUtf8 $ toStrict name) "loadtest.bin" fileUploadPart
let subData = (:) fileData $ formData2 >>= \(name := (renderFormValue -> value)) -> do let subData = (:) fileData $ formData2 >>= \(name := (renderFormValue -> value)) -> do
guard $ name /= encodeUtf8 (fileData ^. partName) guard $ name /= encodeUtf8 (fileData ^. partName)
return $ partBS (decodeUtf8 name) value return $ partBS (decodeUtf8 name) value
@ -307,7 +308,6 @@ runSimulation' LoadSheetSubmission = do
resp3 <- liftIO $ Session.post session (uriToString id formURI mempty) subData resp3 <- liftIO $ Session.post session (uriToString id formURI mempty) subData
void . evaluate $! resp3 void . evaluate $! resp3
-- print $ resp3 ^. responseStatus
-- runSimulation' other = terror $ "Not implemented: " <> tshow other -- runSimulation' other = terror $ "Not implemented: " <> tshow other

View File

@ -1008,6 +1008,7 @@ CommCourseSubject: Kursmitteilung
MailSubjectLecturerInvitation tid@TermId ssh@SchoolId csh@CourseShorthand: [#{tid}-#{ssh}-#{csh}] Einladung zum Kursverwalter MailSubjectLecturerInvitation tid@TermId ssh@SchoolId csh@CourseShorthand: [#{tid}-#{ssh}-#{csh}] Einladung zum Kursverwalter
InvitationAcceptDecline: Einladung annehmen/ablehnen InvitationAcceptDecline: Einladung annehmen/ablehnen
InvitationFromTip displayName@Text: Sie erhalten diese Einladung, weil #{displayName} ihren Versand in Uni2work ausgelöst hat. InvitationFromTip displayName@Text: Sie erhalten diese Einladung, weil #{displayName} ihren Versand in Uni2work ausgelöst hat.
InvitationFromTipAnonymous: Sie erhalten diese Einladung, weil ein nicht eingeloggter Benutzer ihren Versand in Uni2work ausgelöst hat.
InvitationUniWorXTip: Uni2work ist ein webbasiertes Lehrverwaltungssystem der LMU München. InvitationUniWorXTip: Uni2work ist ein webbasiertes Lehrverwaltungssystem der LMU München.
MailSubjectParticipantInvitation tid@TermId ssh@SchoolId csh@CourseShorthand: [#{tid}-#{ssh}-#{csh}] Einladung zur Kursteilnahme MailSubjectParticipantInvitation tid@TermId ssh@SchoolId csh@CourseShorthand: [#{tid}-#{ssh}-#{csh}] Einladung zur Kursteilnahme

View File

@ -332,6 +332,11 @@ SheetGeneratePseudonym: Generate
SheetAnonymousCorrection: Anonymized correction SheetAnonymousCorrection: Anonymized correction
SheetAnonymousCorrectionTip: If correction is anonymized, correctors cannot see which students are involved in submissions that are assigned to them (names, matriculation numbers, and registered submission groups are hidden) SheetAnonymousCorrectionTip: If correction is anonymized, correctors cannot see which students are involved in submissions that are assigned to them (names, matriculation numbers, and registered submission groups are hidden)
SheetArchiveFileTypeDirectoryExercise: exercise
SheetArchiveFileTypeDirectoryHint: hint
SheetArchiveFileTypeDirectorySolution: solution
SheetArchiveFileTypeDirectoryMarking: marking
SheetFormType: Valuation & submission SheetFormType: Valuation & submission
SheetFormTimes: Times SheetFormTimes: Times
SheetFormFiles: Files SheetFormFiles: Files
@ -1004,6 +1009,7 @@ CommCourseSubject: Course message
MailSubjectLecturerInvitation tid ssh csh: [#{tid}-#{ssh}-#{csh}] Invitation to be a course administrator MailSubjectLecturerInvitation tid ssh csh: [#{tid}-#{ssh}-#{csh}] Invitation to be a course administrator
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 Uni2work. InvitationFromTip displayName: You are receiving this invitation because #{displayName} has caused it to be sent from within Uni2work.
InvitationFromTipAnonymous: You are receiving this invitiation because an user who didn't log in has caused it to be send from within Uni2work.
InvitationUniWorXTip: Uni2work is a web based teaching management system at LMU Munich. InvitationUniWorXTip: Uni2work is a web based teaching management system at LMU Munich.
MailSubjectParticipantInvitation tid ssh csh: [#{tid}-#{ssh}-#{csh}] Invitation to be a course participant MailSubjectParticipantInvitation tid ssh csh: [#{tid}-#{ssh}-#{csh}] Invitation to be a course participant

View File

@ -27,7 +27,6 @@ import qualified Network.Wai as W
import qualified Network.HTTP.Types.Header as W import qualified Network.HTTP.Types.Header as W
import qualified Network.Wai.Middleware.HttpAuth as W (extractBearerAuth) import qualified Network.Wai.Middleware.HttpAuth as W (extractBearerAuth)
import Yesod.Core.Types (HandlerContents)
import qualified Yesod.Core.Unsafe as Unsafe import qualified Yesod.Core.Unsafe as Unsafe
import qualified Data.CaseInsensitive as CI import qualified Data.CaseInsensitive as CI
@ -105,7 +104,7 @@ import qualified Web.ServerSession.Frontend.Yesod.Jwt as JwtSession
import Web.Cookie import Web.Cookie
import Yesod.Core.Types (GHState(..), HandlerData(handlerState, handlerEnv), RunHandlerEnv(rheSite, rheChild)) import Yesod.Core.Types (GHState(..), HandlerData(..), HandlerContents, RunHandlerEnv(rheSite, rheChild))
import Database.Persist.Sql (transactionUndo, SqlReadBackend(..)) import Database.Persist.Sql (transactionUndo, SqlReadBackend(..))
-- | Convenient Type Synonyms: -- | Convenient Type Synonyms:
@ -1733,7 +1732,7 @@ instance Yesod UniWorX where
csrfMiddleware handler = do csrfMiddleware handler = do
hasBearer <- is _Just <$> lookupBearerAuth hasBearer <- is _Just <$> lookupBearerAuth
if | hasBearer -> handler if | hasBearer -> local (\HandlerData{..} -> HandlerData{ handlerRequest = handlerRequest { reqToken = Nothing }, .. }) handler
| otherwise -> csrfSetCookieMiddleware' . defaultCsrfCheckMiddleware $ handler | otherwise -> csrfSetCookieMiddleware' . defaultCsrfCheckMiddleware $ handler
where where
csrfSetCookieMiddleware' handler' = do csrfSetCookieMiddleware' handler' = do

View File

@ -212,7 +212,7 @@ sinkInvitations InvitationConfig{..} = determineExists .| sinkInvitations'
fEnt <- Entity fid <$> get404 fid fEnt <- Entity fid <$> get404 fid
jInviter <- liftHandler requireAuthId jInviter <- liftHandler maybeAuthId
route <- mapReaderT liftHandler $ invitationRoute fEnt dat route <- mapReaderT liftHandler $ invitationRoute fEnt dat
InvitationTokenConfig{..} <- mapReaderT liftHandler $ invitationTokenConfig fEnt dat InvitationTokenConfig{..} <- mapReaderT liftHandler $ invitationTokenConfig fEnt dat
protoToken <- bearerToken itAuthority (Just . HashSet.singleton $ urlRoute route) itAddAuth itExpiresAt itStartsAt protoToken <- bearerToken itAuthority (Just . HashSet.singleton $ urlRoute route) itAddAuth itExpiresAt itStartsAt

View File

@ -2,6 +2,7 @@ module Import.NoModel
( module Import ( module Import
, MForm , MForm
, WeekDay , WeekDay
, requireAuthId
) where ) where
import ClassyPrelude.Yesod as Import import ClassyPrelude.Yesod as Import
@ -29,7 +30,7 @@ import Model.Types.TH.Wordlist as Import
import Mail as Import import Mail as Import
import Yesod.Auth as Import import Yesod.Auth as Import hiding (requireAuthId)
import Yesod.Core.Types as Import (loggerSet) import Yesod.Core.Types as Import (loggerSet)
import Yesod.Default.Config2 as Import import Yesod.Default.Config2 as Import
import Yesod.Core.Types.Instances as Import import Yesod.Core.Types.Instances as Import
@ -185,6 +186,14 @@ import GHC.TypeLits as Import (KnownSymbol)
import Control.Monad.Trans.RWS (RWST) import Control.Monad.Trans.RWS (RWST)
import qualified Yesod.Auth as Yesod
import GHC.Stack
type MForm m = RWST (Maybe (Env, FileEnv), HandlerSite m, [Lang]) Enctype Ints m type MForm m = RWST (Maybe (Env, FileEnv), HandlerSite m, [Lang]) Enctype Ints m
type WeekDay = DayOfWeek type WeekDay = DayOfWeek
requireAuthId :: (MonadHandler m, YesodAuth (HandlerSite m), HasCallStack) => m (AuthId (HandlerSite m))
requireAuthId = do
$logDebugS "requireAuthId" . pack $ prettyCallStack callStack
Yesod.requireAuthId

View File

@ -9,18 +9,19 @@ import qualified Data.CaseInsensitive as CI
import Text.Hamlet import Text.Hamlet
dispatchJobInvitation :: UserId dispatchJobInvitation :: Maybe UserId
-> UserEmail -> UserEmail
-> Text -> Text
-> Text -> Text
-> Html -> Html
-> JobHandler UniWorX -> JobHandler UniWorX
dispatchJobInvitation jInviter jInvitee jInvitationUrl jInvitationSubject jInvitationExplanation = JobHandlerException $ do dispatchJobInvitation jInviter jInvitee jInvitationUrl jInvitationSubject jInvitationExplanation = JobHandlerException $ do
mInviter <- runDB $ get jInviter mInviter <- join <$> traverse (runDB . get) jInviter
whenIsJust mInviter $ \jInviter' -> mailT def $ do mailT def $ do
_mailTo .= [Address Nothing $ CI.original jInvitee] _mailTo .= [Address Nothing $ CI.original jInvitee]
replaceMailHeader "Reply-To" . Just . renderAddress $ userAddressFrom jInviter' whenIsJust mInviter $ \jInviter' ->
replaceMailHeader "Reply-To" . Just . renderAddress $ userAddressFrom jInviter'
replaceMailHeader "Auto-Submitted" $ Just "auto-generated" replaceMailHeader "Auto-Submitted" $ Just "auto-generated"
replaceMailHeader "Subject" $ Just jInvitationSubject replaceMailHeader "Subject" $ Just jInvitationSubject
addHtmlMarkdownAlternatives ($(ihamletFile "templates/mail/invitation.hamlet") :: HtmlUrlI18n UniWorXMessage (Route UniWorX)) addHtmlMarkdownAlternatives ($(ihamletFile "templates/mail/invitation.hamlet") :: HtmlUrlI18n UniWorXMessage (Route UniWorX))

View File

@ -58,7 +58,7 @@ data Job = JobSendNotification { jRecipient :: UserId, jNotification :: Notifica
, jSubject :: Maybe Text , jSubject :: Maybe Text
, jMailContent :: Html , jMailContent :: Html
} }
| JobInvitation { jInviter :: UserId | JobInvitation { jInviter :: Maybe UserId
, jInvitee :: UserEmail , jInvitee :: UserEmail
, jInvitationUrl :: Text , jInvitationUrl :: Text
, jInvitationSubject :: Text , jInvitationSubject :: Text

View File

@ -10,6 +10,9 @@ $newline never
<a href=#{jInvitationUrl}> <a href=#{jInvitationUrl}>
_{MsgInvitationAcceptDecline} _{MsgInvitationAcceptDecline}
<p> <p>
_{MsgInvitationFromTip (userDisplayName jInviter')} $maybe inviter <- mInviter
_{MsgInvitationFromTip (userDisplayName inviter)}
$nothing
_{MsgInvitationFromTipAnonymous}
<p> <p>
_{MsgInvitationUniWorXTip} _{MsgInvitationUniWorXTip}