Propagate restriction on 'rated' to file downloads
This commit is contained in:
parent
cc28e6f786
commit
49ae1a3865
@ -207,7 +207,7 @@ correctionsR whereClause (formColonnade -> displayColumns) psValidator actions =
|
|||||||
FormMissing -> return ()
|
FormMissing -> return ()
|
||||||
FormSuccess (CorrDownloadData, subs) -> do
|
FormSuccess (CorrDownloadData, subs) -> do
|
||||||
ids <- Set.fromList <$> forM (Set.toList subs) decrypt -- Set is not traversable
|
ids <- Set.fromList <$> forM (Set.toList subs) decrypt -- Set is not traversable
|
||||||
addHeader "Content-Disposition" "attachment; filename=\"corrections.zip\""
|
addHeader "Content-Disposition" [st|attachment; filename="corrections.zip"|]
|
||||||
sendResponse =<< submissionMultiArchive ids
|
sendResponse =<< submissionMultiArchive ids
|
||||||
FormSuccess (CorrSetCorrectorData (Just uid), subs') -> do
|
FormSuccess (CorrSetCorrectorData (Just uid), subs') -> do
|
||||||
subs <- mapM decrypt $ Set.toList subs'
|
subs <- mapM decrypt $ Set.toList subs'
|
||||||
|
|||||||
@ -274,7 +274,7 @@ getSShowR tid csh shn = do
|
|||||||
|
|
||||||
getSFileR :: TermId -> Text -> Text -> SheetFileType -> FilePath -> Handler TypedContent
|
getSFileR :: TermId -> Text -> Text -> SheetFileType -> FilePath -> Handler TypedContent
|
||||||
getSFileR tid csh shn typ title = do
|
getSFileR tid csh shn typ title = do
|
||||||
content <- runDB $ E.select $ E.from $
|
results <- runDB $ E.select $ E.from $
|
||||||
\(course `E.InnerJoin` sheet `E.InnerJoin` sheetFile `E.InnerJoin` file) -> do
|
\(course `E.InnerJoin` sheet `E.InnerJoin` sheetFile `E.InnerJoin` file) -> do
|
||||||
-- Restrict to consistent rows that correspond to each other
|
-- Restrict to consistent rows that correspond to each other
|
||||||
E.on (file E.^. FileId E.==. sheetFile E.^. SheetFileFile)
|
E.on (file E.^. FileId E.==. sheetFile E.^. SheetFileFile)
|
||||||
@ -288,15 +288,18 @@ getSFileR tid csh shn typ title = do
|
|||||||
E.&&. (course E.^. CourseTerm E.==. E.val tid )
|
E.&&. (course E.^. CourseTerm E.==. E.val tid )
|
||||||
)
|
)
|
||||||
-- return desired columns
|
-- return desired columns
|
||||||
return $ file E.^. FileContent
|
return $ (file E.^. FileTitle, file E.^. FileContent)
|
||||||
let mimeType = defaultMimeLookup $ pack title
|
let mimeType = defaultMimeLookup $ pack title
|
||||||
case content of
|
case results of
|
||||||
[E.Value (Just nochmalContent)] -> do
|
[(E.Value fileTitle, E.Value fileContent)]
|
||||||
addHeader "Content-Disposition" "attachment"
|
| Just fileContent' <- fileContent -> do
|
||||||
respond mimeType nochmalContent
|
addHeader "Content-Disposition" [st|attachment; filename="#{takeFileName fileTitle}"|]
|
||||||
[] -> notFound
|
return $ TypedContent (defaultMimeLookup (pack fileTitle) <> "; charset=utf-8") (toContent fileContent')
|
||||||
_other -> error "Multiple matching files found."
|
| otherwise -> sendResponseStatus noContent204 ()
|
||||||
|
[] -> notFound
|
||||||
|
other -> do
|
||||||
|
$logErrorS "SFileR" $ "Multiple matching files: " <> tshow other
|
||||||
|
error "Multiple matching files found."
|
||||||
|
|
||||||
getSheetNewR :: TermId -> Text -> Handler Html
|
getSheetNewR :: TermId -> Text -> Handler Html
|
||||||
getSheetNewR tid csh = do
|
getSheetNewR tid csh = do
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
{-# LANGUAGE RecordWildCards #-}
|
{-# LANGUAGE RecordWildCards, NamedFieldPuns #-}
|
||||||
{-# LANGUAGE NoImplicitPrelude #-}
|
{-# LANGUAGE NoImplicitPrelude #-}
|
||||||
{-# LANGUAGE OverloadedStrings #-}
|
{-# LANGUAGE OverloadedStrings #-}
|
||||||
{-# LANGUAGE OverloadedLists #-}
|
{-# LANGUAGE OverloadedLists #-}
|
||||||
@ -56,8 +56,6 @@ import Colonnade hiding (bool, fromMaybe)
|
|||||||
import qualified Yesod.Colonnade as Yesod
|
import qualified Yesod.Colonnade as Yesod
|
||||||
import qualified Text.Blaze.Html5.Attributes as HA
|
import qualified Text.Blaze.Html5.Attributes as HA
|
||||||
|
|
||||||
import Text.Shakespeare.Text (st)
|
|
||||||
|
|
||||||
|
|
||||||
numberOfSubmissionEditDates :: Int64
|
numberOfSubmissionEditDates :: Int64
|
||||||
numberOfSubmissionEditDates = 3 -- for debugging only, should be 1 in production.
|
numberOfSubmissionEditDates = 3 -- for debugging only, should be 1 in production.
|
||||||
@ -143,7 +141,7 @@ submissionHelper tid csh shn (SubmissionMode mcid) = do
|
|||||||
addMessageI "info" $ MsgSubmissionAlreadyExists
|
addMessageI "info" $ MsgSubmissionAlreadyExists
|
||||||
redirect $ CSubmissionR tid csh shn cID SubShowR
|
redirect $ CSubmissionR tid csh shn cID SubShowR
|
||||||
(Just smid) -> do
|
(Just smid) -> do
|
||||||
submissionMatchesSheet tid csh shn (fromJust mcid)
|
void $ submissionMatchesSheet tid csh shn (fromJust mcid)
|
||||||
|
|
||||||
shid' <- submissionSheet <$> get404 smid
|
shid' <- submissionSheet <$> get404 smid
|
||||||
-- fetch buddies from current submission
|
-- fetch buddies from current submission
|
||||||
@ -311,40 +309,52 @@ submissionHelper tid csh shn (SubmissionMode mcid) = do
|
|||||||
|
|
||||||
getSubDownloadR :: TermId -> Text -> Text -> CryptoFileNameSubmission -> SubmissionFileType -> FilePath -> Handler TypedContent
|
getSubDownloadR :: TermId -> Text -> Text -> CryptoFileNameSubmission -> SubmissionFileType -> FilePath -> Handler TypedContent
|
||||||
getSubDownloadR tid csh shn cID (submissionFileTypeIsUpdate -> isUpdate) path = do
|
getSubDownloadR tid csh shn cID (submissionFileTypeIsUpdate -> isUpdate) path = do
|
||||||
submissionID <- decrypt cID
|
|
||||||
|
|
||||||
runDB $ do
|
runDB $ do
|
||||||
submissionMatchesSheet tid csh shn cID
|
submissionID <- submissionMatchesSheet tid csh shn cID
|
||||||
|
|
||||||
isRating <- maybe False (== submissionID) <$> isRatingFile path
|
isRating <- maybe False (== submissionID) <$> isRatingFile path
|
||||||
|
|
||||||
|
when (isUpdate || isRating) $
|
||||||
|
guardAuthResult =<< evalAccessDB (CSubmissionR tid csh shn cID CorrectionR) False
|
||||||
|
|
||||||
case isRating of
|
case isRating of
|
||||||
True -> do
|
True
|
||||||
file <- runMaybeT $ lift . ratingFile cID =<< MaybeT (getRating submissionID)
|
| isUpdate -> do
|
||||||
maybe notFound (return . toTypedContent . Text.decodeUtf8) $ fileContent =<< file
|
file <- runMaybeT $ lift . ratingFile cID =<< MaybeT (getRating submissionID)
|
||||||
|
maybe notFound (return . toTypedContent . Text.decodeUtf8) $ fileContent =<< file
|
||||||
|
| otherwise -> notFound
|
||||||
False -> do
|
False -> do
|
||||||
results <- E.select . E.from $ \(sf `E.InnerJoin` f) -> do
|
results <- E.select . E.from $ \(sf `E.InnerJoin` f) -> do
|
||||||
E.on (f E.^. FileId E.==. sf E.^. SubmissionFileFile)
|
E.on (f E.^. FileId E.==. sf E.^. SubmissionFileFile)
|
||||||
E.where_ $ sf E.^. SubmissionFileSubmission E.==. E.val submissionID
|
E.where_ $ sf E.^. SubmissionFileSubmission E.==. E.val submissionID
|
||||||
E.&&. f E.^. FileTitle E.==. E.val path
|
E.&&. f E.^. FileTitle E.==. E.val path
|
||||||
E.&&. E.not_ (E.isNothing $ f E.^. FileContent)
|
|
||||||
E.&&. E.not_ (sf E.^. SubmissionFileIsDeletion)
|
E.&&. E.not_ (sf E.^. SubmissionFileIsDeletion)
|
||||||
E.&&. sf E.^. SubmissionFileIsUpdate E.==. E.val isUpdate
|
E.&&. sf E.^. SubmissionFileIsUpdate E.==. E.val isUpdate
|
||||||
|
-- E.&&. E.not_ (E.isNothing $ f E.^. FileContent) -- This is fine, we just return 204
|
||||||
return f
|
return f
|
||||||
|
|
||||||
let fileName = Text.pack $ takeFileName path
|
let fileName = Text.pack $ takeFileName path
|
||||||
case results of
|
case results of
|
||||||
[Entity _ File{ fileContent = Just c }] -> return $ TypedContent (defaultMimeLookup fileName <> "; charset=utf-8") (toContent c)
|
[Entity _ File{ fileContent = Just c, fileTitle }] -> do
|
||||||
_ -> notFound
|
addHeader "Content-Disposition" [st|attachment; filename="#{takeFileName fileTitle}"|]
|
||||||
|
return $ TypedContent (defaultMimeLookup (pack fileTitle) <> "; charset=utf-8") (toContent c)
|
||||||
|
[Entity _ File{ fileContent = Nothing }] -> sendResponseStatus noContent204 ()
|
||||||
|
other -> do
|
||||||
|
$logErrorS "SubDownloadR" $ "Multiple matching files: " <> tshow other
|
||||||
|
error "Multiple matching files found."
|
||||||
|
|
||||||
getSubArchiveR :: TermId -> Text -> Text -> CryptoFileNameSubmission -> ZIPArchiveName SubmissionFileType -> Handler TypedContent
|
getSubArchiveR :: TermId -> Text -> Text -> CryptoFileNameSubmission -> ZIPArchiveName SubmissionFileType -> Handler TypedContent
|
||||||
getSubArchiveR tid csh shn cID@CryptoID{..} (ZIPArchiveName sfType) = do
|
getSubArchiveR tid csh shn cID@CryptoID{..} (ZIPArchiveName sfType) = do
|
||||||
submissionID <- decrypt cID
|
when (sfType == SubmissionCorrected) $
|
||||||
|
guardAuthResult =<< evalAccess (CSubmissionR tid csh shn cID CorrectionR) False
|
||||||
addHeader "Content-Disposition" [st|attachment; filename="#{toPathPiece cID}-#{toPathPiece sfType}.zip"|]
|
|
||||||
|
|
||||||
|
let filename
|
||||||
|
| SubmissionOriginal <- sfType = ZIPArchiveName $ toPathPiece cID <> "-" <> toPathPiece sfType
|
||||||
|
| otherwise = ZIPArchiveName $ toPathPiece cID
|
||||||
|
|
||||||
|
addHeader "Content-Disposition" [st|attachment; filename="#{toPathPiece filename}"|]
|
||||||
respondSourceDB "application/zip" $ do
|
respondSourceDB "application/zip" $ do
|
||||||
lift $ submissionMatchesSheet tid csh shn cID
|
submissionID <- lift $ submissionMatchesSheet tid csh shn cID
|
||||||
|
|
||||||
rating <- lift $ getRating submissionID
|
rating <- lift $ getRating submissionID
|
||||||
|
|
||||||
let
|
let
|
||||||
@ -361,6 +371,6 @@ getSubArchiveR tid csh shn cID@CryptoID{..} (ZIPArchiveName sfType) = do
|
|||||||
when (sfType == SubmissionCorrected) $
|
when (sfType == SubmissionCorrected) $
|
||||||
maybe (return ()) (yieldM . ratingFile cID) rating
|
maybe (return ()) (yieldM . ratingFile cID) rating
|
||||||
|
|
||||||
zipComment = Text.encodeUtf8 . pack $ CI.foldedCase ciphertext
|
zipComment = Text.encodeUtf8 $ toPathPiece cID
|
||||||
|
|
||||||
fileSource' .| produceZip ZipInfo{..} .| Conduit.map toFlushBuilder
|
fileSource' .| produceZip ZipInfo{..} .| Conduit.map toFlushBuilder
|
||||||
|
|||||||
@ -462,11 +462,7 @@ sinkMultiSubmission userId isUpdate = do
|
|||||||
Submission{..} <- get404 sId
|
Submission{..} <- get404 sId
|
||||||
Sheet{..} <- get404 submissionSheet
|
Sheet{..} <- get404 submissionSheet
|
||||||
Course{..} <- get404 sheetCourse
|
Course{..} <- get404 sheetCourse
|
||||||
authRes <- evalAccessDB (CSubmissionR courseTerm courseShorthand sheetName cID CorrectionR) True
|
guardAuthResult =<< evalAccessDB (CSubmissionR courseTerm courseShorthand sheetName cID CorrectionR) True
|
||||||
case authRes of
|
|
||||||
AuthenticationRequired -> notAuthenticated
|
|
||||||
Unauthorized t -> permissionDenied t
|
|
||||||
Authorized -> return ()
|
|
||||||
return . newResumableSink $ sinkSubmission userId (Right sId) isUpdate
|
return . newResumableSink $ sinkSubmission userId (Right sId) isUpdate
|
||||||
sink' <- lift $ yield val ++$$ sink
|
sink' <- lift $ yield val ++$$ sink
|
||||||
case sink' of
|
case sink' of
|
||||||
@ -512,9 +508,10 @@ sinkMultiSubmission userId isUpdate = do
|
|||||||
handleCryptoID _ = return Nothing
|
handleCryptoID _ = return Nothing
|
||||||
|
|
||||||
|
|
||||||
submissionMatchesSheet :: TermId -> Text -> Text -> CryptoFileNameSubmission -> DB ()
|
submissionMatchesSheet :: TermId -> Text -> Text -> CryptoFileNameSubmission -> DB SubmissionId
|
||||||
submissionMatchesSheet tid csh shn cid = do
|
submissionMatchesSheet tid csh shn cid = do
|
||||||
sid <- decrypt cid
|
sid <- decrypt cid
|
||||||
shid <- fetchSheetId tid csh shn
|
shid <- fetchSheetId tid csh shn
|
||||||
Submission{..} <- get404 sid
|
Submission{..} <- get404 sid
|
||||||
when (shid /= submissionSheet) $ invalidArgsI [MsgSubmissionWrongSheet]
|
when (shid /= submissionSheet) $ invalidArgsI [MsgSubmissionWrongSheet]
|
||||||
|
return sid
|
||||||
|
|||||||
@ -19,3 +19,5 @@ import CryptoID as Import
|
|||||||
import Data.UUID as Import (UUID)
|
import Data.UUID as Import (UUID)
|
||||||
|
|
||||||
import Text.Lucius as Import
|
import Text.Lucius as Import
|
||||||
|
|
||||||
|
import Text.Shakespeare.Text as Import hiding (text, stext)
|
||||||
|
|||||||
@ -51,6 +51,11 @@ instance Monad FormResult where
|
|||||||
(FormFailure errs) >>= _ = FormFailure errs
|
(FormFailure errs) >>= _ = FormFailure errs
|
||||||
(FormSuccess a) >>= f = f a
|
(FormSuccess a) >>= f = f a
|
||||||
|
|
||||||
|
guardAuthResult :: MonadHandler m => AuthResult -> m ()
|
||||||
|
guardAuthResult AuthenticationRequired = notAuthenticated
|
||||||
|
guardAuthResult (Unauthorized t) = permissionDenied t
|
||||||
|
guardAuthResult Authorized = return ()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
---------------------
|
---------------------
|
||||||
|
|||||||
Reference in New Issue
Block a user