fix(downloads): do download links via redirect
This commit is contained in:
parent
7854222a8d
commit
3ba41d8f24
@ -83,15 +83,6 @@ instance Yesod UniWorX where
|
|||||||
Nothing -> getApprootText guessApproot app req
|
Nothing -> getApprootText guessApproot app req
|
||||||
Just root -> root
|
Just root -> root
|
||||||
|
|
||||||
urlParamRenderOverride app route params = do
|
|
||||||
rApproot <- case authoritiveApproot route of
|
|
||||||
ApprootDefault -> mzero
|
|
||||||
rApproot -> return rApproot
|
|
||||||
guard $ views _appRoot ($ ApprootDefault) app /= views _appRoot ($ rApproot) app
|
|
||||||
approotText <- app ^. _appRoot . to ($ rApproot)
|
|
||||||
let (ps, params') = renderRoute route
|
|
||||||
return . joinPath app approotText ps $ params ++ params'
|
|
||||||
|
|
||||||
makeSessionBackend = UniWorX.makeSessionBackend
|
makeSessionBackend = UniWorX.makeSessionBackend
|
||||||
|
|
||||||
maximumContentLength app _ = app ^. _appMaximumContentLength
|
maximumContentLength app _ = app ^. _appMaximumContentLength
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@ -31,7 +31,7 @@ yesodMiddleware :: ( BearerAuthSite UniWorX
|
|||||||
, BackendCompatible SqlBackend (YesodPersistBackend UniWorX)
|
, BackendCompatible SqlBackend (YesodPersistBackend UniWorX)
|
||||||
)
|
)
|
||||||
=> HandlerFor UniWorX res -> HandlerFor UniWorX res
|
=> HandlerFor UniWorX res -> HandlerFor UniWorX res
|
||||||
yesodMiddleware = cacheControlMiddleware . storeBearerMiddleware . csrfMiddleware . dryRunMiddleware . observeYesodCacheSizeMiddleware . languagesMiddleware appLanguages . headerMessagesMiddleware . securityMiddleware . normalizeRouteMiddleware . updateFavouritesMiddleware . setActiveAuthTagsMiddleware
|
yesodMiddleware = cacheControlMiddleware . storeBearerMiddleware . csrfMiddleware . dryRunMiddleware . observeYesodCacheSizeMiddleware . languagesMiddleware appLanguages . headerMessagesMiddleware . securityMiddleware . normalizeRouteMiddleware . updateFavouritesMiddleware . setActiveAuthTagsMiddleware . normalizeApprootMiddleware
|
||||||
where
|
where
|
||||||
dryRunMiddleware :: HandlerFor UniWorX a -> HandlerFor UniWorX a
|
dryRunMiddleware :: HandlerFor UniWorX a -> HandlerFor UniWorX a
|
||||||
dryRunMiddleware handler = do
|
dryRunMiddleware handler = do
|
||||||
@ -135,6 +135,30 @@ yesodMiddleware = cacheControlMiddleware . storeBearerMiddleware . csrfMiddlewar
|
|||||||
handler
|
handler
|
||||||
cacheControlMiddleware :: HandlerFor UniWorX a -> HandlerFor UniWorX a
|
cacheControlMiddleware :: HandlerFor UniWorX a -> HandlerFor UniWorX a
|
||||||
cacheControlMiddleware = (addHeader "Vary" "Accept, Accept-Language" *>)
|
cacheControlMiddleware = (addHeader "Vary" "Accept, Accept-Language" *>)
|
||||||
|
normalizeApprootMiddleware :: HandlerFor UniWorX a -> HandlerFor UniWorX a
|
||||||
|
normalizeApprootMiddleware handler = maybeT handler $ do
|
||||||
|
route <- MaybeT getCurrentRoute
|
||||||
|
reqHost <- MaybeT $ W.requestHeaderHost <$> waiRequest
|
||||||
|
let rApproot = authoritiveApproot route
|
||||||
|
app <- getYesod
|
||||||
|
approotHost <- hoistMaybe $ approotScopeHost rApproot app
|
||||||
|
let doRedirect = do
|
||||||
|
url <- approotRender rApproot route
|
||||||
|
$logErrorS "normalizeApprootMiddleware" url
|
||||||
|
redirect url
|
||||||
|
if | approotHost /= reqHost
|
||||||
|
, rApproot /= ApprootUserGenerated
|
||||||
|
-> doRedirect
|
||||||
|
| approotHost /= reqHost -> do
|
||||||
|
resp <- try $ lift handler
|
||||||
|
$logErrorS "normalizeApprootMiddleware" $ tshow (is _Right resp, preview _Left resp)
|
||||||
|
case resp of
|
||||||
|
Right _ -> doRedirect
|
||||||
|
Left sc | is _HCRedirect sc -> throwM sc
|
||||||
|
Left _ -> doRedirect
|
||||||
|
| otherwise -> lift handler
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
updateFavourites :: forall m backend.
|
updateFavourites :: forall m backend.
|
||||||
( MonadHandler m, HandlerSite m ~ UniWorX
|
( MonadHandler m, HandlerSite m ~ UniWorX
|
||||||
@ -175,8 +199,7 @@ routeNormalizers :: forall m backend.
|
|||||||
, BearerAuthSite UniWorX
|
, BearerAuthSite UniWorX
|
||||||
) => [Route UniWorX -> WriterT Any (ReaderT backend m) (Route UniWorX)]
|
) => [Route UniWorX -> WriterT Any (ReaderT backend m) (Route UniWorX)]
|
||||||
routeNormalizers = map (hoist (hoist liftHandler . withReaderT projectBackend) .)
|
routeNormalizers = map (hoist (hoist liftHandler . withReaderT projectBackend) .)
|
||||||
[ normalizeApproot
|
[ normalizeRender
|
||||||
, normalizeRender
|
|
||||||
, ncSchool
|
, ncSchool
|
||||||
, ncAllocation
|
, ncAllocation
|
||||||
, ncCourse
|
, ncCourse
|
||||||
@ -195,12 +218,6 @@ routeNormalizers = map (hoist (hoist liftHandler . withReaderT projectBackend) .
|
|||||||
, verifyMaterialVideo
|
, verifyMaterialVideo
|
||||||
]
|
]
|
||||||
where
|
where
|
||||||
normalizeApproot route = (route <$) . runMaybeT $ do
|
|
||||||
reqHost <- MaybeT $ W.requestHeaderHost <$> waiRequest
|
|
||||||
approotHost <- MaybeT . getsYesod . approotScopeHost $ authoritiveApproot route
|
|
||||||
when (approotHost /= reqHost) $
|
|
||||||
tell $ Any True
|
|
||||||
|
|
||||||
normalizeRender :: Route UniWorX -> WriterT Any (ReaderT SqlReadBackend (HandlerFor UniWorX)) (Route UniWorX)
|
normalizeRender :: Route UniWorX -> WriterT Any (ReaderT SqlReadBackend (HandlerFor UniWorX)) (Route UniWorX)
|
||||||
normalizeRender route = route <$ do
|
normalizeRender route = route <$ do
|
||||||
YesodRequest{..} <- liftHandler getRequest
|
YesodRequest{..} <- liftHandler getRequest
|
||||||
|
|||||||
@ -13,8 +13,6 @@ import qualified Data.Conduit.Combinators as C
|
|||||||
|
|
||||||
import qualified Database.Esqueleto as E
|
import qualified Database.Esqueleto as E
|
||||||
|
|
||||||
import Handler.Course.Show
|
|
||||||
|
|
||||||
|
|
||||||
data AllocationAddUserForm = AllocationAddUserForm
|
data AllocationAddUserForm = AllocationAddUserForm
|
||||||
{ aauUser :: UserId
|
{ aauUser :: UserId
|
||||||
@ -121,7 +119,7 @@ allocationApplicationsForm aId courses FieldSettings{..} fvRequired = formToAFor
|
|||||||
mApplicationTemplate <- runMaybeT $ do
|
mApplicationTemplate <- runMaybeT $ do
|
||||||
guard hasApplicationTemplate
|
guard hasApplicationTemplate
|
||||||
let Course{..} = course
|
let Course{..} = course
|
||||||
liftHandler . runDB $ toTextUrl <=< withFileDownloadToken (courseRegisterTemplateSource courseTerm courseSchool courseShorthand) $ CourseR courseTerm courseSchool courseShorthand CRegisterTemplateR
|
toTextUrl $ CourseR courseTerm courseSchool courseShorthand CRegisterTemplateR
|
||||||
over _2 (course, allocCourse, mApplicationTemplate, ) <$> applicationForm (Just aId) cId Nothing ApplicationFormMode{..} Nothing
|
over _2 (course, allocCourse, mApplicationTemplate, ) <$> applicationForm (Just aId) cId Nothing ApplicationFormMode{..} Nothing
|
||||||
let appsRes = sequenceA $ view _1 <$> appsRes'
|
let appsRes = sequenceA $ view _1 <$> appsRes'
|
||||||
appsViews = view _2 <$> appsRes'
|
appsViews = view _2 <$> appsRes'
|
||||||
|
|||||||
@ -141,7 +141,7 @@ applicationForm maId@(is _Just -> isAlloc) cid muid ApplicationFormMode{..} mcsr
|
|||||||
appFilesInfo <- for mApp $ \(Entity appId _) -> liftHandler . runDB $ do
|
appFilesInfo <- for mApp $ \(Entity appId _) -> liftHandler . runDB $ do
|
||||||
hasFiles <- exists [ CourseApplicationFileApplication ==. appId ]
|
hasFiles <- exists [ CourseApplicationFileApplication ==. appId ]
|
||||||
appCID <- encrypt appId
|
appCID <- encrypt appId
|
||||||
appFilesLink <- toTextUrl <=< withFileDownloadToken (selectSource [ CourseApplicationFileApplication ==. appId ] []) $ CApplicationR courseTerm courseSchool courseShorthand appCID CAFilesR
|
appFilesLink <- toTextUrl $ CApplicationR courseTerm courseSchool courseShorthand appCID CAFilesR
|
||||||
return (hasFiles, appFilesLink)
|
return (hasFiles, appFilesLink)
|
||||||
let hasFiles = maybe False (view _1) appFilesInfo
|
let hasFiles = maybe False (view _1) appFilesInfo
|
||||||
|
|
||||||
|
|||||||
@ -15,8 +15,6 @@ import Handler.Allocation.Application
|
|||||||
import qualified Database.Esqueleto as E
|
import qualified Database.Esqueleto as E
|
||||||
import qualified Database.Esqueleto.Utils as E
|
import qualified Database.Esqueleto.Utils as E
|
||||||
|
|
||||||
import Handler.Course.Show
|
|
||||||
|
|
||||||
|
|
||||||
data NotifyNewCourseButton
|
data NotifyNewCourseButton
|
||||||
= BtnNotifyNewCourseForceOn
|
= BtnNotifyNewCourseForceOn
|
||||||
@ -178,7 +176,7 @@ postAShowR tid ssh ash = do
|
|||||||
Just (Entity appId _) -> CApplicationR courseTerm courseSchool courseShorthand <$> encrypt appId <*> pure CAEditR
|
Just (Entity appId _) -> CApplicationR courseTerm courseSchool courseShorthand <$> encrypt appId <*> pure CAEditR
|
||||||
mApplicationTemplate <- runMaybeT $ do
|
mApplicationTemplate <- runMaybeT $ do
|
||||||
guard hasApplicationTemplate
|
guard hasApplicationTemplate
|
||||||
liftHandler . runDB $ toTextUrl <=< withFileDownloadToken (courseRegisterTemplateSource courseTerm courseSchool courseShorthand) $ CourseR courseTerm courseSchool courseShorthand CRegisterTemplateR
|
toTextUrl $ CourseR courseTerm courseSchool courseShorthand CRegisterTemplateR
|
||||||
|
|
||||||
let mApplyFormView' = view _1 <$> mApplyFormView
|
let mApplyFormView' = view _1 <$> mApplyFormView
|
||||||
overrideVisible = not mayApply && is _Just mApp
|
overrideVisible = not mayApply && is _Just mApp
|
||||||
|
|||||||
@ -104,7 +104,7 @@ courseRegisterForm (Entity cid Course{..}) = liftHandler $ do
|
|||||||
appFilesInfo <- for application $ \(Entity appId _) -> liftHandler . runDB $ do
|
appFilesInfo <- for application $ \(Entity appId _) -> liftHandler . runDB $ do
|
||||||
hasFiles <- exists [ CourseApplicationFileApplication ==. appId ]
|
hasFiles <- exists [ CourseApplicationFileApplication ==. appId ]
|
||||||
appCID <- encrypt appId
|
appCID <- encrypt appId
|
||||||
appFilesLink <- toTextUrl <=< withFileDownloadToken (selectSource [ CourseApplicationFileApplication ==. appId ] []) $ CApplicationR courseTerm courseSchool courseShorthand appCID CAFilesR
|
appFilesLink <- toTextUrl $ CApplicationR courseTerm courseSchool courseShorthand appCID CAFilesR
|
||||||
return (hasFiles, appFilesLink)
|
return (hasFiles, appFilesLink)
|
||||||
let hasFiles = maybe False (view _1) appFilesInfo
|
let hasFiles = maybe False (view _1) appFilesInfo
|
||||||
filesMsg = bool MsgCourseRegistrationFiles MsgCourseApplicationFiles courseApplicationsRequired
|
filesMsg = bool MsgCourseRegistrationFiles MsgCourseApplicationFiles courseApplicationsRequired
|
||||||
|
|||||||
@ -25,8 +25,6 @@ import qualified Data.Conduit.List as C
|
|||||||
|
|
||||||
import Handler.Exam.List (mkExamTable)
|
import Handler.Exam.List (mkExamTable)
|
||||||
|
|
||||||
import Handler.Course.News.Download
|
|
||||||
|
|
||||||
|
|
||||||
getCShowR :: TermId -> SchoolId -> CourseShorthand -> Handler Html
|
getCShowR :: TermId -> SchoolId -> CourseShorthand -> Handler Html
|
||||||
getCShowR tid ssh csh = do
|
getCShowR tid ssh csh = do
|
||||||
@ -80,7 +78,7 @@ getCShowR tid ssh csh = do
|
|||||||
E.where_ $ courseAppInstructionFile E.^. CourseAppInstructionFileCourse E.==. E.val cid
|
E.where_ $ courseAppInstructionFile E.^. CourseAppInstructionFileCourse E.==. E.val cid
|
||||||
mApplicationTemplate <- runMaybeT $ do
|
mApplicationTemplate <- runMaybeT $ do
|
||||||
guard hasApplicationTemplate
|
guard hasApplicationTemplate
|
||||||
lift . lift $ toTextUrl <=< withFileDownloadToken (courseRegisterTemplateSource tid ssh csh) $ CourseR tid ssh csh CRegisterTemplateR
|
lift . lift . toTextUrl $ CourseR tid ssh csh CRegisterTemplateR
|
||||||
mApplication <- lift . fmap (listToMaybe =<<) . for mbAid $ \uid -> selectList [CourseApplicationCourse ==. cid, CourseApplicationUser ==. uid, CourseApplicationAllocation ==. Nothing] []
|
mApplication <- lift . fmap (listToMaybe =<<) . for mbAid $ \uid -> selectList [CourseApplicationCourse ==. cid, CourseApplicationUser ==. uid, CourseApplicationAllocation ==. Nothing] []
|
||||||
news' <- lift $ selectList [ CourseNewsCourse ==. cid ] [ Desc CourseNewsVisibleFrom, Desc CourseNewsTitle, Desc CourseNewsSummary, Desc CourseNewsContent ]
|
news' <- lift $ selectList [ CourseNewsCourse ==. cid ] [ Desc CourseNewsVisibleFrom, Desc CourseNewsTitle, Desc CourseNewsSummary, Desc CourseNewsContent ]
|
||||||
cTime <- NTop . Just <$> liftIO getCurrentTime
|
cTime <- NTop . Just <$> liftIO getCurrentTime
|
||||||
@ -98,8 +96,8 @@ getCShowR tid ssh csh = do
|
|||||||
mayEditNews <- hasWriteAccessTo $ CNewsR tid ssh csh cID CNEditR
|
mayEditNews <- hasWriteAccessTo $ CNewsR tid ssh csh cID CNEditR
|
||||||
mayDelete <- hasWriteAccessTo $ CNewsR tid ssh csh cID CNDeleteR
|
mayDelete <- hasWriteAccessTo $ CNewsR tid ssh csh cID CNDeleteR
|
||||||
|
|
||||||
files <- lift . lift $ forM files'' $ \f@(_isDir, fPath) -> fmap (f ,) . toTextUrl <=< withFileDownloadToken (cnFileSource nId fPath) . CNewsR tid ssh csh cID $ CNFileR fPath
|
files <- lift . lift $ forM files'' $ \f@(_isDir, fPath) -> fmap (f ,) . toTextUrl . CNewsR tid ssh csh cID $ CNFileR fPath
|
||||||
archiveUrl <- lift . lift $ toTextUrl <=< withFileDownloadToken (cnArchiveSource nId) $ CNewsR tid ssh csh cID CNArchiveR
|
archiveUrl <- lift . lift . toTextUrl $ CNewsR tid ssh csh cID CNArchiveR
|
||||||
|
|
||||||
return (cID, n, visible, files, lastEditText, mayEditNews, mayDelete, archiveUrl)
|
return (cID, n, visible, files, lastEditText, mayEditNews, mayDelete, archiveUrl)
|
||||||
|
|
||||||
|
|||||||
@ -83,9 +83,8 @@ getMaterialListR tid ssh csh = do
|
|||||||
let matLink :: MaterialName -> Route UniWorX
|
let matLink :: MaterialName -> Route UniWorX
|
||||||
matLink = CourseR tid ssh csh . flip MaterialR MShowR
|
matLink = CourseR tid ssh csh . flip MaterialR MShowR
|
||||||
|
|
||||||
filesLink :: (MonadHandler m, HandlerSite m ~ UniWorX)
|
filesLink :: MaterialName -> SomeRoute UniWorX
|
||||||
=> MaterialName -> m (SomeRoute UniWorX)
|
filesLink mnm = SomeRoute . CourseR tid ssh csh $ MaterialR mnm MArchiveR
|
||||||
filesLink mnm = liftHandler . runDB $ withFileDownloadToken (materialArchiveSource tid ssh csh mnm) . CourseR tid ssh csh $ MaterialR mnm MArchiveR
|
|
||||||
|
|
||||||
materialModDateCell :: IsDBTable m a => Material -> DBCell m a
|
materialModDateCell :: IsDBTable m a => Material -> DBCell m a
|
||||||
materialModDateCell Material{materialVisibleFrom, materialLastEdit}
|
materialModDateCell Material{materialVisibleFrom, materialLastEdit}
|
||||||
@ -124,7 +123,7 @@ getMaterialListR tid ssh csh = do
|
|||||||
, sortable (toNothingS "zip-archive") (mempty & cellAttrs <>~ pure ("uw-hide-columns--hider-label", mr MsgMaterialFiles))
|
, sortable (toNothingS "zip-archive") (mempty & cellAttrs <>~ pure ("uw-hide-columns--hider-label", mr MsgMaterialFiles))
|
||||||
$ \DBRow{ dbrOutput = (Entity _ Material{..}, E.Value fileNum) } -> if
|
$ \DBRow{ dbrOutput = (Entity _ Material{..}, E.Value fileNum) } -> if
|
||||||
| fileNum == 0 -> mempty
|
| fileNum == 0 -> mempty
|
||||||
| otherwise -> anchorCellM (filesLink materialName) iconFileDownload
|
| otherwise -> anchorCell (filesLink materialName) iconFileDownload
|
||||||
, sortable (Just "visible-from") (i18nCell MsgAccessibleSince)
|
, sortable (Just "visible-from") (i18nCell MsgAccessibleSince)
|
||||||
$ foldMap (dateTimeCellVisible now) . materialVisibleFrom . row2material
|
$ foldMap (dateTimeCellVisible now) . materialVisibleFrom . row2material
|
||||||
, sortable (Just "last-edit") (i18nCell MsgFileModified)
|
, sortable (Just "last-edit") (i18nCell MsgFileModified)
|
||||||
@ -177,10 +176,10 @@ getMFileR tid ssh csh mnm title = serveOneFile $ fileQuery .| C.map entityVal
|
|||||||
getMVideoR :: TermId -> SchoolId -> CourseShorthand -> MaterialName -> CryptoUUIDMaterialFile -> Handler Html
|
getMVideoR :: TermId -> SchoolId -> CourseShorthand -> MaterialName -> CryptoUUIDMaterialFile -> Handler Html
|
||||||
getMVideoR tid ssh csh mnm cID = do
|
getMVideoR tid ssh csh mnm cID = do
|
||||||
mfId <- decrypt cID
|
mfId <- decrypt cID
|
||||||
mf@MaterialFile{..} <- runDB $ get404 mfId
|
MaterialFile{..} <- runDB $ get404 mfId
|
||||||
let mimeType = mimeLookup $ pack materialFileTitle
|
let mimeType = mimeLookup $ pack materialFileTitle
|
||||||
mfile <- withFileDownloadToken (views (_FileReference . _1) yield mf) . CMaterialR tid ssh csh mnm $ MFileR materialFileTitle
|
mfile = CMaterialR tid ssh csh mnm $ MFileR materialFileTitle
|
||||||
let mfileDownload = mfile & over (urlRouteParams $ Proxy @UniWorX) (\params -> bool ((toPathPiece GetDownload, mempty) : ) id (anyOf (folded . _1) (== toPathPiece GetDownload) params) params)
|
let mfileDownload = mfile & over (urlRouteParams $ Proxy @UniWorX) (\params -> bool ((toPathPiece GetDownload, toPathPiece True) : ) id (anyOf (folded . _1) (== toPathPiece GetDownload) params) params)
|
||||||
mfileText <- toTextUrl mfile
|
mfileText <- toTextUrl mfile
|
||||||
mfileDownloadText <- toTextUrl mfileDownload
|
mfileDownloadText <- toTextUrl mfileDownload
|
||||||
unless (mimeType `Set.member` videoTypes) $
|
unless (mimeType `Set.member` videoTypes) $
|
||||||
@ -206,7 +205,7 @@ getMShowR tid ssh csh mnm = do
|
|||||||
seeAllModificationTimestamps <- hasReadAccessTo $ CourseR tid ssh csh CNotesR -- ordinary users should not see modification dates older than visibility
|
seeAllModificationTimestamps <- hasReadAccessTo $ CourseR tid ssh csh CNotesR -- ordinary users should not see modification dates older than visibility
|
||||||
|
|
||||||
(Entity _mid material@Material{materialType, materialDescription}, (Any hasFiles,fileTable), zipLink) <- runDB $ do
|
(Entity _mid material@Material{materialType, materialDescription}, (Any hasFiles,fileTable), zipLink) <- runDB $ do
|
||||||
zipLink <- withFileDownloadToken (materialArchiveSource tid ssh csh mnm) $ CMaterialR tid ssh csh mnm MArchiveR
|
let zipLink = CMaterialR tid ssh csh mnm MArchiveR
|
||||||
matEnt <- fetchMaterial tid ssh csh mnm
|
matEnt <- fetchMaterial tid ssh csh mnm
|
||||||
let materialModDateCol :: (IsDBTable m c) => (t -> E.Value UTCTime) -> Colonnade Sortable t (DBCell m c)
|
let materialModDateCol :: (IsDBTable m c) => (t -> E.Value UTCTime) -> Colonnade Sortable t (DBCell m c)
|
||||||
materialModDateCol = if seeAllModificationTimestamps
|
materialModDateCol = if seeAllModificationTimestamps
|
||||||
@ -220,12 +219,12 @@ getMShowR tid ssh csh mnm = do
|
|||||||
return matFile
|
return matFile
|
||||||
, dbtRowKey = (E.^. MaterialFileId)
|
, dbtRowKey = (E.^. MaterialFileId)
|
||||||
, dbtColonnade = widgetColonnade $ mconcat
|
, dbtColonnade = widgetColonnade $ mconcat
|
||||||
[ fmap (<> indicatorCell) . sortable (Just "path") (i18nCell MsgFileTitle) $ \(dbrOutput -> Entity mfId mf@MaterialFile{..})
|
[ fmap (<> indicatorCell) . sortable (Just "path") (i18nCell MsgFileTitle) $ \(dbrOutput -> Entity mfId MaterialFile{..})
|
||||||
-> let matLink
|
-> let matLink
|
||||||
| isVideo
|
| isVideo
|
||||||
= SomeRoute . CourseR tid ssh csh . MaterialR mnm . MVideoR <$> encrypt mfId
|
= CourseR tid ssh csh . MaterialR mnm . MVideoR <$> encrypt mfId
|
||||||
| otherwise
|
| otherwise
|
||||||
= withFileDownloadToken (views (_FileReference . _1) yield mf) . CMaterialR tid ssh csh mnm $ MFileR materialFileTitle
|
= pure . CMaterialR tid ssh csh mnm $ MFileR materialFileTitle
|
||||||
wgt = [whamlet|
|
wgt = [whamlet|
|
||||||
$newline never
|
$newline never
|
||||||
<span .file-path>
|
<span .file-path>
|
||||||
|
|||||||
@ -54,10 +54,10 @@ getSheetListR tid ssh csh = do
|
|||||||
[ icnCell & addIconFixedWidth
|
[ icnCell & addIconFixedWidth
|
||||||
| let existingSFTs = hasSFT existFiles
|
| let existingSFTs = hasSFT existFiles
|
||||||
, sft <- [minBound..maxBound]
|
, sft <- [minBound..maxBound]
|
||||||
, let link = liftHandler . runDB . withFileDownloadToken (sheetFilesAllQuery tid ssh csh sheetName muid sft) . CSheetR tid ssh csh sheetName $ SZipR sft
|
, let link = CSheetR tid ssh csh sheetName $ SZipR sft
|
||||||
, let icn = toWgt $ sheetFile2markup sft
|
, let icn = toWgt $ sheetFile2markup sft
|
||||||
, let icnCell = if sft `elem` existingSFTs
|
, let icnCell = if sft `elem` existingSFTs
|
||||||
then linkEitherCellM link (icn, [whamlet| |])
|
then linkEitherCell link (icn, [whamlet| |])
|
||||||
else spacerCell
|
else spacerCell
|
||||||
] id & cellAttrs <>~ [("class","list--inline list--space-separated")]
|
] id & cellAttrs <>~ [("class","list--inline list--space-separated")]
|
||||||
, sortable (Just "submission-since") (i18nCell MsgSheetActiveFrom)
|
, sortable (Just "submission-since") (i18nCell MsgSheetActiveFrom)
|
||||||
|
|||||||
@ -50,14 +50,14 @@ getSShowR tid ssh csh shn = do
|
|||||||
)
|
)
|
||||||
let colonnadeFiles = widgetColonnade $ mconcat
|
let colonnadeFiles = widgetColonnade $ mconcat
|
||||||
[ sortable (Just "type") (i18nCell MsgSheetFileTypeHeader) $ \(_,_, E.Value ftype, _) ->
|
[ sortable (Just "type") (i18nCell MsgSheetFileTypeHeader) $ \(_,_, E.Value ftype, _) ->
|
||||||
let link = liftHandler . runDB . withFileDownloadToken (sheetFilesAllQuery tid ssh csh shn muid ftype) . CSheetR tid ssh csh shn $ SZipR ftype
|
let link = CSheetR tid ssh csh shn $ SZipR ftype
|
||||||
in tellCell (Any True) $
|
in tellCell (Any True) $
|
||||||
anchorCellM link [whamlet|#{sheetFile2markup ftype} _{ftype}|]
|
anchorCell link [whamlet|#{sheetFile2markup ftype} _{ftype}|]
|
||||||
-- i18nCell ftype & cellContents %~ (\act -> act <* tell (Any True))
|
-- i18nCell ftype & cellContents %~ (\act -> act <* tell (Any True))
|
||||||
|
|
||||||
-- , colFilePath (view _1) (\row -> let fType = view _3 row in let fName = view _1 row in (CSheetR tid ssh csh shn (SFileR (E.unValue fType) (E.unValue fName))))
|
-- , colFilePath (view _1) (\row -> let fType = view _3 row in let fName = view _1 row in (CSheetR tid ssh csh shn (SFileR (E.unValue fType) (E.unValue fName))))
|
||||||
, sortable (Just "path") (i18nCell MsgFileTitle) $ \(E.Value fName,E.Value fMod,E.Value fType, E.Value fRef) -> anchorCellM
|
, sortable (Just "path") (i18nCell MsgFileTitle) $ \(E.Value fName, _, E.Value fType, _) -> anchorCell
|
||||||
(withFileDownloadToken (yield $ FileReference fName fRef fMod) $ CSheetR tid ssh csh shn (SFileR fType fName))
|
(CSheetR tid ssh csh shn $ SFileR fType fName)
|
||||||
(str2widget fName)
|
(str2widget fName)
|
||||||
, sortable (toNothing "visible") (i18nCell MsgVisibleFrom)
|
, sortable (toNothing "visible") (i18nCell MsgVisibleFrom)
|
||||||
$ \(_, _ , E.Value ftype, _) -> sftVisible ftype
|
$ \(_, _ , E.Value ftype, _) -> sftVisible ftype
|
||||||
|
|||||||
@ -17,8 +17,6 @@ import qualified Control.Monad.State.Class as State
|
|||||||
import qualified Database.Esqueleto as E
|
import qualified Database.Esqueleto as E
|
||||||
import qualified Database.Esqueleto.Utils as E
|
import qualified Database.Esqueleto.Utils as E
|
||||||
|
|
||||||
import Handler.Submission.Download
|
|
||||||
|
|
||||||
|
|
||||||
correctionData :: TermId -> SchoolId -> CourseShorthand -> SheetName -> _ -- CryptoFileNameSubmission -> _
|
correctionData :: TermId -> SchoolId -> CourseShorthand -> SheetName -> _ -- CryptoFileNameSubmission -> _
|
||||||
correctionData tid ssh csh shn sub = E.select . E.from $ \((course `E.InnerJoin` sheet `E.InnerJoin` submission) `E.LeftOuterJoin` corrector) -> do
|
correctionData tid ssh csh shn sub = E.select . E.from $ \((course `E.InnerJoin` sheet `E.InnerJoin` submission) `E.LeftOuterJoin` corrector) -> do
|
||||||
@ -146,7 +144,7 @@ postCorrectionR tid ssh csh shn cid = do
|
|||||||
|]
|
|]
|
||||||
siteLayout headingWgt $ do
|
siteLayout headingWgt $ do
|
||||||
setTitleI heading
|
setTitleI heading
|
||||||
urlArchive <- toTextUrl <=< liftHandler . runDB . withFileDownloadToken' (subArchiveSource tid ssh csh shn cid SubmissionCorrected) . CSubmissionR tid ssh csh shn cid $ SubArchiveR SubmissionCorrected
|
urlArchive <- toTextUrl . CSubmissionR tid ssh csh shn cid $ SubArchiveR SubmissionCorrected
|
||||||
let userCorrection = $(widgetFile "correction-user")
|
let userCorrection = $(widgetFile "correction-user")
|
||||||
$(widgetFile "correction")
|
$(widgetFile "correction")
|
||||||
_ -> notFound
|
_ -> notFound
|
||||||
@ -159,6 +157,6 @@ getCorrectionUserR tid ssh csh shn cid = do
|
|||||||
[(Entity _ Course{..}, Entity _ Sheet{..}, Entity _ Submission{..}, corrector@(Just _), E.Value filesCorrected)] ->
|
[(Entity _ Course{..}, Entity _ Sheet{..}, Entity _ Submission{..}, corrector@(Just _), E.Value filesCorrected)] ->
|
||||||
let ratingComment = assertM (not . null) $ Text.strip <$> submissionRatingComment
|
let ratingComment = assertM (not . null) $ Text.strip <$> submissionRatingComment
|
||||||
in defaultLayout $ do
|
in defaultLayout $ do
|
||||||
urlArchive <- toTextUrl <=< liftHandler . runDB . withFileDownloadToken' (subArchiveSource courseTerm courseSchool courseShorthand sheetName cid SubmissionCorrected) . CSubmissionR courseTerm courseSchool courseShorthand sheetName cid $ SubArchiveR SubmissionCorrected
|
urlArchive <- toTextUrl . CSubmissionR courseTerm courseSchool courseShorthand sheetName cid $ SubArchiveR SubmissionCorrected
|
||||||
$(widgetFile "correction-user")
|
$(widgetFile "correction-user")
|
||||||
_ -> notFound
|
_ -> notFound
|
||||||
|
|||||||
@ -27,8 +27,6 @@ import Text.Blaze (Markup)
|
|||||||
import qualified Data.Aeson.Types as JSON
|
import qualified Data.Aeson.Types as JSON
|
||||||
import Data.Aeson.Lens
|
import Data.Aeson.Lens
|
||||||
|
|
||||||
|
|
||||||
import Handler.Submission.Download
|
|
||||||
import Handler.Submission.SubmissionUserInvite
|
import Handler.Submission.SubmissionUserInvite
|
||||||
|
|
||||||
|
|
||||||
@ -491,12 +489,12 @@ submissionHelper tid ssh csh shn mcid = do
|
|||||||
corrIsFile = fmap (isJust . submissionFileContent . entityVal) mCorr
|
corrIsFile = fmap (isJust . submissionFileContent . entityVal) mCorr
|
||||||
Just isFile = origIsFile <|> corrIsFile
|
Just isFile = origIsFile <|> corrIsFile
|
||||||
in if
|
in if
|
||||||
| Just True <- origIsFile -> anchorCellM (subDownloadLink cid SubmissionOriginal fileTitle') [whamlet|#{fileTitle'}|]
|
| Just True <- origIsFile -> anchorCell (subDownloadLink cid SubmissionOriginal fileTitle') [whamlet|#{fileTitle'}|]
|
||||||
| otherwise -> textCell $ bool (<> "/") id isFile fileTitle'
|
| otherwise -> textCell $ bool (<> "/") id isFile fileTitle'
|
||||||
, guardOn showCorrection . sortable (toNothing "state") (i18nCell MsgCorState) $ \(_, mCorr) -> case mCorr of
|
, guardOn showCorrection . sortable (toNothing "state") (i18nCell MsgCorState) $ \(_, mCorr) -> case mCorr of
|
||||||
Nothing -> cell mempty
|
Nothing -> cell mempty
|
||||||
Just (Entity _ SubmissionFile{..})
|
Just (Entity _ SubmissionFile{..})
|
||||||
| isJust submissionFileContent -> anchorCellM (subDownloadLink cid SubmissionCorrected submissionFileTitle) (i18n MsgFileCorrected :: Widget)
|
| isJust submissionFileContent -> anchorCell (subDownloadLink cid SubmissionCorrected submissionFileTitle) (i18n MsgFileCorrected :: Widget)
|
||||||
| otherwise -> i18nCell MsgCorrected
|
| otherwise -> i18nCell MsgCorrected
|
||||||
, Just . sortable (Just "time") (i18nCell MsgFileModified) $ \(mOrig, mCorr) -> let
|
, Just . sortable (Just "time") (i18nCell MsgFileModified) $ \(mOrig, mCorr) -> let
|
||||||
origTime = submissionFileModified . entityVal <$> mOrig
|
origTime = submissionFileModified . entityVal <$> mOrig
|
||||||
@ -504,8 +502,7 @@ submissionHelper tid ssh csh shn mcid = do
|
|||||||
Just fileTime = (max <$> origTime <*> corrTime) <|> origTime <|> corrTime
|
Just fileTime = (max <$> origTime <*> corrTime) <|> origTime <|> corrTime
|
||||||
in dateTimeCell fileTime
|
in dateTimeCell fileTime
|
||||||
]
|
]
|
||||||
subDownloadLink :: _ -> _ -> _ -> WidgetFor UniWorX _
|
subDownloadLink cid sft fileTitle' = CSubmissionR tid ssh csh shn cid $ SubDownloadR sft fileTitle'
|
||||||
subDownloadLink cid sft fileTitle' = liftHandler . runDB . withFileDownloadToken (subDownloadSource tid ssh csh shn cid sft fileTitle') . CSubmissionR tid ssh csh shn cid $ SubDownloadR sft fileTitle'
|
|
||||||
submissionFiles :: _ -> _ -> E.SqlQuery _
|
submissionFiles :: _ -> _ -> E.SqlQuery _
|
||||||
submissionFiles smid (sf1 `E.FullOuterJoin` sf2) = do
|
submissionFiles smid (sf1 `E.FullOuterJoin` sf2) = do
|
||||||
E.on $ sf1 E.?. SubmissionFileTitle E.==. sf2 E.?. SubmissionFileTitle
|
E.on $ sf1 E.?. SubmissionFileTitle E.==. sf2 E.?. SubmissionFileTitle
|
||||||
@ -555,7 +552,7 @@ submissionHelper tid ssh csh shn mcid = do
|
|||||||
defaultLayout $ do
|
defaultLayout $ do
|
||||||
setTitleI $ MsgSubmissionEditHead tid ssh csh shn
|
setTitleI $ MsgSubmissionEditHead tid ssh csh shn
|
||||||
(urlArchive, urlOriginal) <- fmap ((,) <$> preview (_Just . _1) <*> preview (_Just . _2)) . for mcid $ \cID
|
(urlArchive, urlOriginal) <- fmap ((,) <$> preview (_Just . _1) <*> preview (_Just . _2)) . for mcid $ \cID
|
||||||
-> let mkUrl sft = toTextUrl <=< withFileDownloadToken' (subArchiveSource tid ssh csh shn cID sft) . CSubmissionR tid ssh csh shn cID $ SubArchiveR sft
|
-> let mkUrl sft = toTextUrl . CSubmissionR tid ssh csh shn cID $ SubArchiveR sft
|
||||||
in liftHandler . runDB $ (,) <$> mkUrl SubmissionCorrected <*> mkUrl SubmissionOriginal
|
in liftHandler . runDB $ (,) <$> mkUrl SubmissionCorrected <*> mkUrl SubmissionOriginal
|
||||||
let correctionWdgt = guardOnM (showCorrection && maybe False submissionRatingDone msubmission) ((,) <$> msubmission <*> mcid) <&> \(Submission{..}, cid) ->
|
let correctionWdgt = guardOnM (showCorrection && maybe False submissionRatingDone msubmission) ((,) <$> msubmission <*> mcid) <&> \(Submission{..}, cid) ->
|
||||||
let ratingComment = assertM (not . null) $ Text.strip <$> submissionRatingComment
|
let ratingComment = assertM (not . null) $ Text.strip <$> submissionRatingComment
|
||||||
|
|||||||
@ -18,6 +18,6 @@ downloadFiles = do
|
|||||||
|
|
||||||
setContentDisposition' :: (MonadHandler m, HandlerSite m ~ UniWorX, YesodAuthPersist UniWorX, AuthEntity UniWorX ~ User, AuthId UniWorX ~ UserId) => Maybe FilePath -> m ()
|
setContentDisposition' :: (MonadHandler m, HandlerSite m ~ UniWorX, YesodAuthPersist UniWorX, AuthEntity UniWorX ~ User, AuthId UniWorX ~ UserId) => Maybe FilePath -> m ()
|
||||||
setContentDisposition' mFileName = do
|
setContentDisposition' mFileName = do
|
||||||
wantsDownload <- or2M (hasGlobalGetParam GetDownload) downloadFiles
|
wantsDownload <- maybeT downloadFiles . MaybeT $ lookupGlobalGetParam GetDownload
|
||||||
setContentDisposition (bool ContentInline ContentAttachment wantsDownload) mFileName
|
setContentDisposition (bool ContentInline ContentAttachment wantsDownload) mFileName
|
||||||
|
|
||||||
|
|||||||
@ -1,6 +1,5 @@
|
|||||||
module Handler.Utils.Download
|
module Handler.Utils.Download
|
||||||
( withFileDownloadTokenMaybe', withFileDownloadToken, withFileDownloadToken'
|
( sendThisFile
|
||||||
, sendThisFile
|
|
||||||
, sendFileReference
|
, sendFileReference
|
||||||
, serveOneFile
|
, serveOneFile
|
||||||
, serveSomeFiles
|
, serveSomeFiles
|
||||||
@ -22,6 +21,8 @@ import Handler.Utils.Zip
|
|||||||
import Handler.Utils.ContentDisposition
|
import Handler.Utils.ContentDisposition
|
||||||
import Handler.Utils.Files
|
import Handler.Utils.Files
|
||||||
|
|
||||||
|
import qualified Network.Wai as W
|
||||||
|
|
||||||
|
|
||||||
data DownloadTokenRestriction
|
data DownloadTokenRestriction
|
||||||
= DownloadRestrictSingle { downloadRestrictReference :: FileContentReference }
|
= DownloadRestrictSingle { downloadRestrictReference :: FileContentReference }
|
||||||
@ -70,55 +71,90 @@ withFileDownloadTokenMaybe' mSource route = maybeT (return $ SomeRoute route) $
|
|||||||
encodedBearer <- lift $ encodeBearer bearer
|
encodedBearer <- lift $ encodeBearer bearer
|
||||||
|
|
||||||
lift . setDownload $ SomeRoute @UniWorX route
|
lift . setDownload $ SomeRoute @UniWorX route
|
||||||
& over (urlRouteParams $ Proxy @UniWorX) ((toPathPiece GetBearer, toPathPiece encodedBearer) :)
|
& over (urlRouteParams $ Proxy @UniWorX) (((toPathPiece GetBearer, toPathPiece encodedBearer) :) . filter (views _1 (maybe False (/= GetBearer) . fromPathPiece)))
|
||||||
|
|
||||||
where
|
where
|
||||||
setDownload :: SomeRoute UniWorX -> m (SomeRoute UniWorX)
|
setDownload :: SomeRoute UniWorX -> m (SomeRoute UniWorX)
|
||||||
setDownload route' = do
|
setDownload route' = do
|
||||||
wantsDownload <- downloadFiles
|
wantsDownload <- downloadFiles
|
||||||
|
defWantsDownload <- getsYesod $ views _appUserDefaults userDefaultDownloadFiles
|
||||||
|
let
|
||||||
|
addDownload params
|
||||||
|
| anyOf (folded . _1) (== toPathPiece GetDownload) params = params
|
||||||
|
| otherwise = (toPathPiece GetDownload, toPathPiece wantsDownload) : params
|
||||||
return $ route'
|
return $ route'
|
||||||
& over (urlRouteParams $ Proxy @UniWorX) (bool id addDownload wantsDownload)
|
& over (urlRouteParams $ Proxy @UniWorX) (bool id addDownload $ wantsDownload /= defWantsDownload)
|
||||||
where
|
|
||||||
addDownload params | anyOf (folded . _1) (== toPathPiece GetDownload) params = params
|
|
||||||
| otherwise = (toPathPiece GetDownload, mempty) : params
|
|
||||||
|
|
||||||
withFileDownloadToken' :: forall file url m.
|
-- withFileDownloadToken' :: forall file url m.
|
||||||
( HasFileReference file
|
-- ( HasFileReference file
|
||||||
, HasRoute UniWorX url
|
-- , HasRoute UniWorX url
|
||||||
, MonadHandler m, HandlerSite m ~ UniWorX
|
-- , MonadHandler m, HandlerSite m ~ UniWorX
|
||||||
, MonadCrypto m
|
-- , MonadCrypto m
|
||||||
, MonadCryptoKey m ~ CryptoIDKey
|
-- , MonadCryptoKey m ~ CryptoIDKey
|
||||||
, YesodAuthPersist UniWorX, AuthEntity UniWorX ~ User, AuthId UniWorX ~ UserId
|
-- , YesodAuthPersist UniWorX, AuthEntity UniWorX ~ User, AuthId UniWorX ~ UserId
|
||||||
)
|
-- )
|
||||||
=> ConduitT () (Either file DBFile) m ()
|
-- => ConduitT () (Either file DBFile) m ()
|
||||||
-> url
|
-- -> url
|
||||||
-> m (SomeRoute UniWorX)
|
-- -> m (SomeRoute UniWorX)
|
||||||
withFileDownloadToken' = withFileDownloadTokenMaybe' . Just . (.| C.map (first . view $ _FileReference . _1))
|
-- withFileDownloadToken' = withFileDownloadTokenMaybe' . Just . (.| C.map (first . view $ _FileReference . _1))
|
||||||
|
|
||||||
|
|
||||||
withFileDownloadToken :: forall file url m.
|
-- withFileDownloadToken :: forall file url m.
|
||||||
( HasFileReference file
|
-- ( HasFileReference file
|
||||||
, HasRoute UniWorX url
|
-- , HasRoute UniWorX url
|
||||||
, MonadHandler m, HandlerSite m ~ UniWorX
|
-- , MonadHandler m, HandlerSite m ~ UniWorX
|
||||||
, MonadCrypto m
|
-- , MonadCrypto m
|
||||||
, MonadCryptoKey m ~ CryptoIDKey
|
-- , MonadCryptoKey m ~ CryptoIDKey
|
||||||
, BearerAuthSite UniWorX
|
-- , BearerAuthSite UniWorX
|
||||||
)
|
-- )
|
||||||
=> ConduitT () file m ()
|
-- => ConduitT () file m ()
|
||||||
-> url
|
-- -> url
|
||||||
-> m (SomeRoute UniWorX)
|
-- -> m (SomeRoute UniWorX)
|
||||||
withFileDownloadToken = withFileDownloadToken' . (.| C.map Left)
|
-- withFileDownloadToken = withFileDownloadToken' . (.| C.map Left)
|
||||||
|
|
||||||
|
ensureApprootUserGeneratedMaybe'
|
||||||
|
:: forall m.
|
||||||
|
( MonadHandler m, HandlerSite m ~ UniWorX
|
||||||
|
, MonadCrypto m
|
||||||
|
, MonadCryptoKey m ~ CryptoIDKey
|
||||||
|
, YesodAuthPersist UniWorX, AuthEntity UniWorX ~ User, AuthId UniWorX ~ UserId
|
||||||
|
)
|
||||||
|
=> Maybe (ConduitT () (Either FileReference DBFile) m ())
|
||||||
|
-> m ()
|
||||||
|
ensureApprootUserGeneratedMaybe' source = maybeT (return ()) $ do
|
||||||
|
route <- (,) <$> MaybeT getCurrentRoute <*> fmap reqGetParams getRequest
|
||||||
|
$logErrorS "ensureApproot" $ tshow route
|
||||||
|
rApproot <- hoistMaybe <=< lift . runMaybeT $ do
|
||||||
|
reqHost <- MaybeT $ W.requestHeaderHost <$> waiRequest
|
||||||
|
let rApproot = authoritiveApproot $ urlRoute route
|
||||||
|
guard $ rApproot == ApprootUserGenerated
|
||||||
|
approotHost <- MaybeT . getsYesod $ approotScopeHost rApproot
|
||||||
|
guard $ approotHost /= reqHost
|
||||||
|
return rApproot
|
||||||
|
$logErrorS "ensureApproot" $ tshow rApproot
|
||||||
|
route' <- lift $ withFileDownloadTokenMaybe' source route
|
||||||
|
url <- approotRender rApproot route'
|
||||||
|
$logErrorS "ensureApprootUserGenerated" url
|
||||||
|
redirect url
|
||||||
|
|
||||||
|
|
||||||
-- | Simply send a `File`-Value
|
-- | Simply send a `File`-Value
|
||||||
sendThisFile :: (YesodAuthPersist UniWorX, AuthEntity UniWorX ~ User, AuthId UniWorX ~ UserId, YesodPersistRunner UniWorX) => DBFile -> HandlerFor UniWorX TypedContent
|
sendThisFile :: ( YesodAuthPersist UniWorX
|
||||||
sendThisFile File{..}
|
, AuthEntity UniWorX ~ User
|
||||||
| Just fileContent' <- fileContent = do
|
, AuthId UniWorX ~ UserId
|
||||||
setCSPSandbox
|
, YesodPersistRunner UniWorX
|
||||||
setContentDisposition' . Just $ takeFileName fileTitle
|
, MonadCrypto (HandlerFor UniWorX), MonadCryptoKey (HandlerFor UniWorX) ~ CryptoIDKey
|
||||||
let cType = simpleContentType (mimeLookup $ pack fileTitle) <> "; charset=utf-8"
|
) => DBFile -> HandlerFor UniWorX TypedContent
|
||||||
respondSourceDB cType $
|
sendThisFile File{..} = do
|
||||||
fileContent' .| C.map toFlushBuilder
|
ensureApprootUserGeneratedMaybe' Nothing
|
||||||
| otherwise = sendResponseStatus noContent204 ()
|
if
|
||||||
|
| Just fileContent' <- fileContent -> do
|
||||||
|
setCSPSandbox
|
||||||
|
setContentDisposition' . Just $ takeFileName fileTitle
|
||||||
|
let cType = simpleContentType (mimeLookup $ pack fileTitle) <> "; charset=utf-8"
|
||||||
|
respondSourceDB cType $
|
||||||
|
fileContent' .| C.map toFlushBuilder
|
||||||
|
| otherwise -> sendResponseStatus noContent204 ()
|
||||||
|
|
||||||
sendFileReference :: forall file a.
|
sendFileReference :: forall file a.
|
||||||
( HasFileReference file
|
( HasFileReference file
|
||||||
@ -128,6 +164,7 @@ sendFileReference :: forall file a.
|
|||||||
)
|
)
|
||||||
=> file -> HandlerFor UniWorX a
|
=> file -> HandlerFor UniWorX a
|
||||||
sendFileReference (view (_FileReference . _1) -> fRef@FileReference{..}) = do
|
sendFileReference (view (_FileReference . _1) -> fRef@FileReference{..}) = do
|
||||||
|
ensureApprootUserGeneratedMaybe' . Just . yield $ Left fRef
|
||||||
whenIsJust fileReferenceContent $ \fRef' -> do
|
whenIsJust fileReferenceContent $ \fRef' -> do
|
||||||
dlRestr <- maybeCurrentBearerRestrictions
|
dlRestr <- maybeCurrentBearerRestrictions
|
||||||
case dlRestr of
|
case dlRestr of
|
||||||
@ -146,6 +183,7 @@ serveOneFile :: forall file.
|
|||||||
) => ConduitT () file (YesodDB UniWorX) () -> HandlerFor UniWorX TypedContent
|
) => ConduitT () file (YesodDB UniWorX) () -> HandlerFor UniWorX TypedContent
|
||||||
serveOneFile source = do
|
serveOneFile source = do
|
||||||
results <- runDB . runConduit $ source .| C.take 2 .| C.foldMap pure -- We don't need more than two files to make a decision below
|
results <- runDB . runConduit $ source .| C.take 2 .| C.foldMap pure -- We don't need more than two files to make a decision below
|
||||||
|
ensureApprootUserGeneratedMaybe' . Just . yieldMany $ map (views (_FileReference . _1) Left) results
|
||||||
case results of
|
case results of
|
||||||
[file] -> sendFileReference file
|
[file] -> sendFileReference file
|
||||||
[] -> notFound
|
[] -> notFound
|
||||||
@ -172,6 +210,7 @@ serveSomeFiles' :: forall file.
|
|||||||
) => FilePath -> ConduitT () (Either file DBFile) (YesodDB UniWorX) () -> HandlerFor UniWorX TypedContent
|
) => FilePath -> ConduitT () (Either file DBFile) (YesodDB UniWorX) () -> HandlerFor UniWorX TypedContent
|
||||||
serveSomeFiles' archiveName source = do
|
serveSomeFiles' archiveName source = do
|
||||||
(source', results) <- runDB $ runPeekN 2 source
|
(source', results) <- runDB $ runPeekN 2 source
|
||||||
|
ensureApprootUserGeneratedMaybe' . Just . yieldMany $ over (traverse . _Left) (view $ _FileReference . _1) results
|
||||||
|
|
||||||
$logDebugS "serveSomeFiles" . tshow $ length results
|
$logDebugS "serveSomeFiles" . tshow $ length results
|
||||||
|
|
||||||
|
|||||||
@ -25,7 +25,6 @@ import Handler.Utils.Form
|
|||||||
import Handler.Utils.Widgets
|
import Handler.Utils.Widgets
|
||||||
import Handler.Utils.DateTime
|
import Handler.Utils.DateTime
|
||||||
import Handler.Utils.StudyFeatures
|
import Handler.Utils.StudyFeatures
|
||||||
import Handler.Utils.Download
|
|
||||||
|
|
||||||
import qualified Data.CaseInsensitive as CI
|
import qualified Data.CaseInsensitive as CI
|
||||||
|
|
||||||
@ -376,7 +375,7 @@ colApplicationFiles resultInfo = Colonnade.singleton (fromSortable header) body
|
|||||||
| showLink
|
| showLink
|
||||||
-> flip anchorCellM (asWidgetT $ toWidget iconApplicationFiles) $ do
|
-> flip anchorCellM (asWidgetT $ toWidget iconApplicationFiles) $ do
|
||||||
cID <- encrypt appId
|
cID <- encrypt appId
|
||||||
liftHandler . runDB . withFileDownloadToken (selectSource [ CourseApplicationFileApplication ==. appId ] []) $ CApplicationR tid ssh csh cID CAFilesR
|
return $ CApplicationR tid ssh csh cID CAFilesR
|
||||||
| otherwise
|
| otherwise
|
||||||
-> mempty
|
-> mempty
|
||||||
|
|
||||||
|
|||||||
@ -60,22 +60,6 @@ data WorkflowCurrentState = WorkflowCurrentState
|
|||||||
|
|
||||||
makePrisms ''WorkflowHistoryItemActor'
|
makePrisms ''WorkflowHistoryItemActor'
|
||||||
|
|
||||||
data OneOrMany a = None | One a | Many
|
|
||||||
deriving (Eq, Ord, Read, Show, Functor, Traversable, Foldable, Generic, Typeable)
|
|
||||||
|
|
||||||
instance Semigroup (OneOrMany a) where
|
|
||||||
None <> x = x
|
|
||||||
x <> None = x
|
|
||||||
_ <> _ = Many
|
|
||||||
instance Monoid (OneOrMany a) where
|
|
||||||
mempty = None
|
|
||||||
|
|
||||||
oneOrMany :: b -> (a -> b) -> b -> OneOrMany a -> b
|
|
||||||
oneOrMany onNone onOne onMany = \case
|
|
||||||
None -> onNone
|
|
||||||
One x -> onOne x
|
|
||||||
Many -> onMany
|
|
||||||
|
|
||||||
|
|
||||||
getGWWWorkflowR, postGWWWorkflowR :: CryptoFileNameWorkflowWorkflow -> Handler Html
|
getGWWWorkflowR, postGWWWorkflowR :: CryptoFileNameWorkflowWorkflow -> Handler Html
|
||||||
getGWWWorkflowR = postGWWWorkflowR
|
getGWWWorkflowR = postGWWWorkflowR
|
||||||
@ -198,13 +182,13 @@ workflowR rScope cID = do
|
|||||||
<> (compareUnicode `on` userDisplayName) uA uB
|
<> (compareUnicode `on` userDisplayName) uA uB
|
||||||
<> comparing userIdent uA uB
|
<> comparing userIdent uA uB
|
||||||
(WFPUser{}, _ ) -> GT
|
(WFPUser{}, _ ) -> GT
|
||||||
forM payload' $ \(lblText, (otoList -> payloads, fRoute)) -> fmap ((lblText, ) . over _1 (sortBy payloadSort)) . mapMOf _2 (traverse toTextUrl <=< oneOrMany (return Nothing) (\fRef -> Just <$> withFileDownloadToken (yield fRef) fRoute) (Just <$> withFileDownloadTokenMaybe' Nothing fRoute)) <=< execWriterT @_ @(_, OneOrMany FileReference). forM_ payloads $ \case
|
forM payload' $ \(lblText, (otoList -> payloads, fRoute)) -> fmap ((lblText, ) . over _1 (sortBy payloadSort)) . mapMOf _2 (traverse toTextUrl . bool Nothing (Just fRoute) . getAny) <=< execWriterT @_ @(_, Any). forM_ payloads $ \case
|
||||||
WorkflowFieldPayloadW (WFPText t ) -> tell . (, mempty) . pure $ WorkflowFieldPayloadW (WFPText t)
|
WorkflowFieldPayloadW (WFPText t ) -> tell . (, mempty) . pure $ WorkflowFieldPayloadW (WFPText t)
|
||||||
WorkflowFieldPayloadW (WFPNumber n ) -> tell . (, mempty) . pure $ WorkflowFieldPayloadW (WFPNumber n)
|
WorkflowFieldPayloadW (WFPNumber n ) -> tell . (, mempty) . pure $ WorkflowFieldPayloadW (WFPNumber n)
|
||||||
WorkflowFieldPayloadW (WFPBool b ) -> tell . (, mempty) . pure $ WorkflowFieldPayloadW (WFPBool b)
|
WorkflowFieldPayloadW (WFPBool b ) -> tell . (, mempty) . pure $ WorkflowFieldPayloadW (WFPBool b)
|
||||||
WorkflowFieldPayloadW (WFPDay d ) -> tell . (, mempty) . pure $ WorkflowFieldPayloadW (WFPDay d)
|
WorkflowFieldPayloadW (WFPDay d ) -> tell . (, mempty) . pure $ WorkflowFieldPayloadW (WFPDay d)
|
||||||
WorkflowFieldPayloadW (WFPFile fRef) -> tell (mempty, One fRef)
|
WorkflowFieldPayloadW (WFPFile _ ) -> tell (mempty, Any True)
|
||||||
WorkflowFieldPayloadW (WFPUser uid ) -> tell . (, mempty) . pure . review (_WorkflowFieldPayloadW . _WorkflowFieldPayload) =<< lift (lift . lift $ getEntity uid)
|
WorkflowFieldPayloadW (WFPUser uid) -> tell . (, mempty) . pure . review (_WorkflowFieldPayloadW . _WorkflowFieldPayload) =<< lift (lift . lift $ getEntity uid)
|
||||||
|
|
||||||
payloadChanges <- State.state $ \oldPayload ->
|
payloadChanges <- State.state $ \oldPayload ->
|
||||||
( Map.filterWithKey (\k v -> Map.findWithDefault Set.empty k oldPayload /= v) currentPayload
|
( Map.filterWithKey (\k v -> Map.findWithDefault Set.empty k oldPayload /= v) currentPayload
|
||||||
|
|||||||
@ -1,18 +1,44 @@
|
|||||||
module Utils.Approot
|
module Utils.Approot
|
||||||
( approotScopeHost
|
( approotScopeHost, approotScopeBaseUrl, approotScopeHost'
|
||||||
|
, approotRender
|
||||||
) where
|
) where
|
||||||
|
|
||||||
import ClassyPrelude
|
import ClassyPrelude.Yesod hiding (Proxy)
|
||||||
import Settings
|
import Settings
|
||||||
|
|
||||||
|
import Utils.Route
|
||||||
|
|
||||||
|
import Network.URI (URI(URI), URIAuth(URIAuth))
|
||||||
import qualified Network.URI as URI
|
import qualified Network.URI as URI
|
||||||
|
|
||||||
import Control.Lens
|
import Control.Lens
|
||||||
|
|
||||||
|
import Data.Proxy
|
||||||
|
|
||||||
approotScopeHost :: HasAppSettings site => ApprootScope -> site -> Maybe ByteString
|
|
||||||
approotScopeHost rApproot app = do
|
approotScopeHost' :: HasAppSettings site => (URI -> URIAuth -> a) -> ApprootScope -> site -> Maybe a
|
||||||
|
approotScopeHost' f rApproot app = do
|
||||||
approotText <- views _appRoot ($ rApproot) app
|
approotText <- views _appRoot ($ rApproot) app
|
||||||
approotURI <- URI.parseURI $ unpack approotText
|
approotURI <- URI.parseURI $ unpack approotText
|
||||||
approotAuthority <- URI.uriAuthority approotURI
|
approotAuthority <- URI.uriAuthority approotURI
|
||||||
return . encodeUtf8 . pack $ URI.uriRegName approotAuthority <> URI.uriPort approotAuthority
|
return $ f approotURI approotAuthority
|
||||||
|
|
||||||
|
approotScopeHost :: HasAppSettings site => ApprootScope -> site -> Maybe ByteString
|
||||||
|
approotScopeHost = approotScopeHost' $ \_ URIAuth{..}
|
||||||
|
-> encodeUtf8 . pack $ uriRegName <> uriPort
|
||||||
|
|
||||||
|
approotScopeBaseUrl :: HasAppSettings site => ApprootScope -> site -> Maybe Text
|
||||||
|
approotScopeBaseUrl = approotScopeHost' $ \URI{..} URIAuth{..}
|
||||||
|
-> pack $ uriScheme <> "//" <> uriRegName <> uriPort
|
||||||
|
|
||||||
|
approotRender :: forall url m.
|
||||||
|
( HasAppSettings (HandlerSite m)
|
||||||
|
, MonadHandler m
|
||||||
|
, Yesod (HandlerSite m)
|
||||||
|
, HasRoute (HandlerSite m) url
|
||||||
|
)
|
||||||
|
=> ApprootScope -> url -> m Text
|
||||||
|
approotRender rApproot route = do
|
||||||
|
app <- getYesod
|
||||||
|
approotHost <- maybe (getApprootText approot app <$> waiRequest) return $ approotScopeBaseUrl rApproot app
|
||||||
|
return . yesodRender app approotHost (urlRoute route) . withLens (urlRouteParams (Proxy @(HandlerSite m))) $ \g _ -> g route
|
||||||
|
|||||||
@ -1,10 +1,13 @@
|
|||||||
|
{-# LANGUAGE UndecidableInstances #-}
|
||||||
|
|
||||||
module Utils.Route where
|
module Utils.Route where
|
||||||
|
|
||||||
import Control.Lens
|
import Control.Lens
|
||||||
import ClassyPrelude.Yesod -- hiding (foldlM)
|
import ClassyPrelude.Yesod hiding (Proxy)
|
||||||
import Data.Kind (Type)
|
import Data.Kind (Type)
|
||||||
|
|
||||||
import qualified Data.Map as Map
|
import qualified Data.Map as Map
|
||||||
|
import Data.Proxy
|
||||||
|
|
||||||
|
|
||||||
class RedirectUrl site url => HasRoute site url where
|
class RedirectUrl site url => HasRoute site url where
|
||||||
@ -46,3 +49,5 @@ instance HasRoute site (SomeRoute site) where
|
|||||||
type RouteWithParams site (SomeRoute site) = SomeRoute site
|
type RouteWithParams site (SomeRoute site) = SomeRoute site
|
||||||
urlRoute (SomeRoute url) = urlRoute url
|
urlRoute (SomeRoute url) = urlRoute url
|
||||||
urlRouteParams pSite = lens (\(SomeRoute url) -> withLens (urlRouteParams pSite) $ \g _ -> g url) (\(SomeRoute url) params -> SomeRoute (urlRoute url :: Route site, params))
|
urlRouteParams pSite = lens (\(SomeRoute url) -> withLens (urlRouteParams pSite) $ \g _ -> g url) (\(SomeRoute url) params -> SomeRoute (urlRoute url :: Route site, params))
|
||||||
|
instance Eq (Route site) => Eq (SomeRoute site) where
|
||||||
|
(==) = (==) `on` (\(SomeRoute r) -> withLens (urlRouteParams $ Proxy @site) $ \g _ -> (urlRoute r :: Route site, sort $ g r))
|
||||||
|
|||||||
Reference in New Issue
Block a user