feat(invitations): anonymous invitations
This commit is contained in:
parent
9a2cba5c0a
commit
1380d9d21e
@ -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
|
||||||
|
|||||||
@ -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
|
||||||
|
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
@ -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))
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
@ -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}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user