refactor: unify FileUploads type

This commit is contained in:
Gregor Kleen 2019-11-04 15:20:34 +01:00
parent 954bb78aae
commit 766ca63b40
5 changed files with 34 additions and 22 deletions

View File

@ -52,7 +52,7 @@ data ApplicationForm = ApplicationForm
{ afPriority :: Maybe Natural { afPriority :: Maybe Natural
, afField :: Maybe StudyFeaturesId , afField :: Maybe StudyFeaturesId
, afText :: Maybe Text , afText :: Maybe Text
, afFiles :: Maybe (ConduitT () File Handler ()) , afFiles :: Maybe FileUploads
, afRatingVeto :: Bool , afRatingVeto :: Bool
, afRatingPoints :: Maybe ExamGrade , afRatingPoints :: Maybe ExamGrade
, afRatingComment :: Maybe Text , afRatingComment :: Maybe Text
@ -291,8 +291,9 @@ editApplicationR maId uid cid mAppId afMode allowAction postAction = do
, courseApplicationRatingTime = guardOn rated now , courseApplicationRatingTime = guardOn rated now
} }
let let
sinkFile' file = do sinkFile' (Right file) =
fId <- insert file insert file >>= sinkFile' . Left
sinkFile' (Left fId) =
insert_ $ CourseApplicationFile appId fId insert_ $ CourseApplicationFile appId fId
forM_ afFiles $ \afFiles' -> forM_ afFiles $ \afFiles' ->
runConduit $ transPipe liftHandler afFiles' .| C.mapM_ sinkFile' runConduit $ transPipe liftHandler afFiles' .| C.mapM_ sinkFile'
@ -308,7 +309,7 @@ editApplicationR maId uid cid mAppId afMode allowAction postAction = do
| afmApplicantEdit afMode -> do | afmApplicantEdit afMode -> do
oldFiles <- Set.fromList . map (courseApplicationFileFile . entityVal) <$> selectList [CourseApplicationFileApplication ==. appId] [] oldFiles <- Set.fromList . map (courseApplicationFileFile . entityVal) <$> selectList [CourseApplicationFileApplication ==. appId] []
changes <- flip execStateT oldFiles . forM_ afFiles $ \afFiles' -> changes <- flip execStateT oldFiles . forM_ afFiles $ \afFiles' ->
let sinkFile' file = do let sinkFile' (Right file) = do
oldFiles' <- lift . E.select . E.from $ \(courseApplicationFile `E.InnerJoin` file') -> do oldFiles' <- lift . E.select . E.from $ \(courseApplicationFile `E.InnerJoin` file') -> do
E.on $ courseApplicationFile E.^. CourseApplicationFileFile E.==. file' E.^. FileId E.on $ courseApplicationFile E.^. CourseApplicationFileFile E.==. file' E.^. FileId
E.where_ $ file' E.^. FileTitle E.==. E.val (fileTitle file) E.where_ $ file' E.^. FileTitle E.==. E.val (fileTitle file)
@ -326,7 +327,12 @@ editApplicationR maId uid cid mAppId afMode allowAction postAction = do
fId <- lift $ insert file fId <- lift $ insert file
lift . insert_ $ CourseApplicationFile appId fId lift . insert_ $ CourseApplicationFile appId fId
modify $ Set.insert fId modify $ Set.insert fId
in runConduit $ transPipe liftHandler afFiles' .| C.mapM_ sinkFile' sinkFile' (Left fId)
| fId `Set.member` oldFiles = modify $ Set.delete fId
| otherwise = do
lift . insert_ $ CourseApplicationFile appId fId
modify $ Set.insert fId
in runConduit $ transPipe liftHandler afFiles' .| C.mapM_ sinkFile'
deleteCascadeWhere [ FileId <-. Set.toList (oldFiles `Set.intersection` changes) ] deleteCascadeWhere [ FileId <-. Set.toList (oldFiles `Set.intersection` changes) ]
return changes return changes
| otherwise | otherwise

View File

@ -57,6 +57,8 @@ import qualified Control.Monad.State.Class as State
import Data.Foldable (foldrM) import Data.Foldable (foldrM)
import qualified Data.Conduit.List as C
type CorrectionTableExpr = (E.SqlExpr (Entity Course) `E.InnerJoin` E.SqlExpr (Entity Sheet) `E.InnerJoin` E.SqlExpr (Entity Submission)) `E.LeftOuterJoin` E.SqlExpr (Maybe (Entity User)) type CorrectionTableExpr = (E.SqlExpr (Entity Course) `E.InnerJoin` E.SqlExpr (Entity Sheet) `E.InnerJoin` E.SqlExpr (Entity Submission)) `E.LeftOuterJoin` E.SqlExpr (Maybe (Entity User))
@ -770,7 +772,7 @@ postCorrectionR tid ssh csh shn cid = do
formResult uploadResult $ \fileUploads -> do formResult uploadResult $ \fileUploads -> do
uid <- requireAuthId uid <- requireAuthId
res <- msgSubmissionErrors . runDBJobs . runConduit $ transPipe (lift . lift) fileUploads .| extractRatingsMsg .| sinkSubmission uid (Right sub) True res <- msgSubmissionErrors . runDBJobs . runConduit $ transPipe (lift . lift) fileUploads .| C.mapM (either get404 return) .| extractRatingsMsg .| sinkSubmission uid (Right sub) True
case res of case res of
Nothing -> return () -- ErrorMessages are already added by msgSubmissionErrors Nothing -> return () -- ErrorMessages are already added by msgSubmissionErrors
(Just _) -> do (Just _) -> do
@ -818,7 +820,7 @@ postCorrectionsUploadR = do
FormFailure errs -> mapM_ (addMessage Error . toHtml) errs FormFailure errs -> mapM_ (addMessage Error . toHtml) errs
FormSuccess files -> do FormSuccess files -> do
uid <- requireAuthId uid <- requireAuthId
mbSubs <- msgSubmissionErrors . runDBJobs . runConduit $ transPipe (lift . lift) files .| extractRatingsMsg .| sinkMultiSubmission uid True mbSubs <- msgSubmissionErrors . runDBJobs . runConduit $ transPipe (lift . lift) files .| C.mapM (either get404 return) .| extractRatingsMsg .| sinkMultiSubmission uid True
case mbSubs of case mbSubs of
Nothing -> return () Nothing -> return ()
(Just subs) (Just subs)

View File

@ -42,7 +42,7 @@ instance Button UniWorX ButtonCourseRegister where
data CourseRegisterForm = CourseRegisterForm data CourseRegisterForm = CourseRegisterForm
{ crfStudyFeatures :: Maybe StudyFeaturesId { crfStudyFeatures :: Maybe StudyFeaturesId
, crfApplicationText :: Maybe Text , crfApplicationText :: Maybe Text
, crfApplicationFiles :: Maybe (ConduitT () File Handler ()) , crfApplicationFiles :: Maybe FileUploads
} }
courseRegisterForm :: (MonadHandler m, HandlerSite m ~ UniWorX) => Entity Course -> m (AForm Handler CourseRegisterForm, ButtonCourseRegister) courseRegisterForm :: (MonadHandler m, HandlerSite m ~ UniWorX) => Entity Course -> m (AForm Handler CourseRegisterForm, ButtonCourseRegister)
@ -195,7 +195,7 @@ postCRegisterR tid ssh csh = do
whenIsJust appRes $ whenIsJust appRes $
audit . TransactionCourseApplicationEdit cid uid audit . TransactionCourseApplicationEdit cid uid
whenIsJust ((,) <$> appRes <*> crfApplicationFiles) $ \(appId, fSource) -> do whenIsJust ((,) <$> appRes <*> crfApplicationFiles) $ \(appId, fSource) -> do
runConduit $ transPipe liftHandler fSource .| C.mapM_ (\f -> insert f >>= insert_ . CourseApplicationFile appId) runConduit $ transPipe liftHandler fSource .| C.mapM_ (insert_ . CourseApplicationFile appId <=< either return insert)
return appRes return appRes
| otherwise | otherwise
= return $ Just () = return $ Just ()

View File

@ -125,7 +125,7 @@ submissionUserInvitationConfig = InvitationConfig{..}
return . SomeRoute $ CSubmissionR courseTerm courseSchool courseShorthand sheetName cID SubShowR return . SomeRoute $ CSubmissionR courseTerm courseSchool courseShorthand sheetName cID SubShowR
makeSubmissionForm :: CourseId -> Maybe SubmissionId -> UploadMode -> SheetGroup -> Bool -> Set (Either UserEmail UserId) -> Form (Maybe (ConduitT () File Handler ()), Set (Either UserEmail UserId)) makeSubmissionForm :: CourseId -> Maybe SubmissionId -> UploadMode -> SheetGroup -> Bool -> Set (Either UserEmail UserId) -> Form (Maybe FileUploads, Set (Either UserEmail UserId))
makeSubmissionForm cid msmid uploadMode grouping isLecturer prefillUsers = identifyForm FIDsubmission . renderAForm FormStandard $ (,) makeSubmissionForm cid msmid uploadMode grouping isLecturer prefillUsers = identifyForm FIDsubmission . renderAForm FormStandard $ (,)
<$> fileUploadForm (not isLecturer && is _Nothing msmid) (fslI . bool MsgSubmissionFile MsgSubmissionArchive) uploadMode <$> fileUploadForm (not isLecturer && is _Nothing msmid) (fslI . bool MsgSubmissionFile MsgSubmissionArchive) uploadMode
<*> wFormToAForm submittorsForm <*> wFormToAForm submittorsForm
@ -428,7 +428,7 @@ submissionHelper tid ssh csh shn mcid = do
(Nothing, Just smid) -- no new files, existing submission partners updated (Nothing, Just smid) -- no new files, existing submission partners updated
-> return smid -> return smid
(Just files, _) -> -- new files (Just files, _) -> -- new files
runConduit $ transPipe (lift . lift) files .| extractRatingsMsg .| sinkSubmission uid (maybe (Left shid) Right msmid) False runConduit $ transPipe (lift . lift) files .| Conduit.mapM (either get404 return) .| extractRatingsMsg .| sinkSubmission uid (maybe (Left shid) Right msmid) False
(Nothing, Nothing) -- new submission, no file upload requested (Nothing, Nothing) -- new submission, no file upload requested
-> do -> do
sid <- insert Submission sid <- insert Submission

View File

@ -643,13 +643,17 @@ pseudonymWordField = checkMMap doCheck id $ ciField & addDatalist (return $ mkOp
| otherwise | otherwise
= return . Left $ MsgUnknownPseudonymWord (CI.original w) = return . Left $ MsgUnknownPseudonymWord (CI.original w)
specificFileField :: UploadSpecificFile -> Field Handler (ConduitT () File Handler ())
type FileUploads = ConduitT () (Either FileId File) Handler ()
specificFileField :: UploadSpecificFile -> Field Handler FileUploads
specificFileField UploadSpecificFile{..} = Field{..} specificFileField UploadSpecificFile{..} = Field{..}
where where
fieldEnctype = Multipart fieldEnctype = Multipart
fieldParse _ files fieldParse _ files
| [f] <- files | [f] <- files
= return . Right . Just $ yieldM (acceptFile f) .| modifyFileTitle (const $ unpack specificFileName) = return . Right . Just $ yieldM (acceptFile f) .| modifyFileTitle (const $ unpack specificFileName) .| C.map Right
| null files = return $ Right Nothing | null files = return $ Right Nothing
| otherwise = return . Left $ SomeMessage MsgOnlyUploadOneFile | otherwise = return . Left $ SomeMessage MsgOnlyUploadOneFile
fieldView fieldId fieldName attrs _ req = $(widgetFile "widgets/specificFileField") fieldView fieldId fieldName attrs _ req = $(widgetFile "widgets/specificFileField")
@ -661,14 +665,14 @@ specificFileField UploadSpecificFile{..} = Field{..}
zipFileField :: Bool -- ^ Unpack zips? zipFileField :: Bool -- ^ Unpack zips?
-> Maybe (NonNull (Set Extension)) -- ^ Restrictions on file extensions -> Maybe (NonNull (Set Extension)) -- ^ Restrictions on file extensions
-> Field Handler (ConduitT () File Handler ()) -> Field Handler FileUploads
zipFileField doUnpack permittedExtensions = Field{..} zipFileField doUnpack permittedExtensions = Field{..}
where where
fieldEnctype = Multipart fieldEnctype = Multipart
fieldParse _ files fieldParse _ files
| [f@FileInfo{..}] <- files | [f@FileInfo{..}] <- files
, maybe True (anyOf (re _nullable . folded . unpacked) ((flip isExtensionOf `on` CI.foldCase) $ unpack fileName)) permittedExtensions || doUnpack , maybe True (anyOf (re _nullable . folded . unpacked) ((flip isExtensionOf `on` CI.foldCase) $ unpack fileName)) permittedExtensions || doUnpack
= return . Right . Just $ bool (yieldM . acceptFile) sourceFiles doUnpack f = return . Right . Just $ bool (yieldM . fmap Right . acceptFile) ((.| C.map Right) . sourceFiles) doUnpack f
| null files = return $ Right Nothing | null files = return $ Right Nothing
| otherwise = return . Left $ SomeMessage MsgOnlyUploadOneFile | otherwise = return . Left $ SomeMessage MsgOnlyUploadOneFile
fieldView fieldId fieldName attrs _ req = $(widgetFile "widgets/zipFileField") fieldView fieldId fieldName attrs _ req = $(widgetFile "widgets/zipFileField")
@ -680,7 +684,7 @@ zipFileField doUnpack permittedExtensions = Field{..}
fileUploadForm :: Bool -- ^ Required? fileUploadForm :: Bool -- ^ Required?
-> (Bool -> FieldSettings UniWorX) -- ^ given @unpackZips@ generate `FieldSettings` in the case of `UploadAny` -> (Bool -> FieldSettings UniWorX) -- ^ given @unpackZips@ generate `FieldSettings` in the case of `UploadAny`
-> UploadMode -> AForm Handler (Maybe (ConduitT () File Handler ())) -> UploadMode -> AForm Handler (Maybe FileUploads)
fileUploadForm isReq mkFs = \case fileUploadForm isReq mkFs = \case
NoUpload NoUpload
-> pure Nothing -> pure Nothing
@ -689,21 +693,21 @@ fileUploadForm isReq mkFs = \case
UploadSpecific{..} UploadSpecific{..}
-> mergeFileSources <$> sequenceA (map specificFileForm . Set.toList $ toNullable specificFiles) -> mergeFileSources <$> sequenceA (map specificFileForm . Set.toList $ toNullable specificFiles)
where where
specificFileForm :: UploadSpecificFile -> AForm Handler (Maybe (ConduitT () File Handler ())) specificFileForm :: UploadSpecificFile -> AForm Handler (Maybe FileUploads)
specificFileForm spec@UploadSpecificFile{..} specificFileForm spec@UploadSpecificFile{..}
= bool (\f fs d -> aopt f fs $ fmap Just d) (\f fs d -> Just <$> areq f fs d) specificFileRequired (specificFileField spec) (fsl specificFileLabel) Nothing = bool (\f fs d -> aopt f fs $ fmap Just d) (\f fs d -> Just <$> areq f fs d) specificFileRequired (specificFileField spec) (fsl specificFileLabel) Nothing
mergeFileSources :: [Maybe (ConduitT () File Handler ())] -> Maybe (ConduitT () File Handler ()) mergeFileSources :: [Maybe FileUploads] -> Maybe FileUploads
mergeFileSources (catMaybes -> sources) = case sources of mergeFileSources (catMaybes -> sources) = case sources of
[] -> Nothing [] -> Nothing
fs -> Just $ sequence_ fs fs -> Just $ sequence_ fs
multiFileField' :: ConduitT () (Either FileId File) Handler () -- ^ Permitted files in same format as produced by `multiFileField` multiFileField' :: FileUploads -- ^ Permitted files in same format as produced by `multiFileField`
-> Field Handler (ConduitT () (Either FileId File) Handler ()) -> Field Handler FileUploads
multiFileField' permittedFiles = multiFileField . runConduit $ permittedFiles .| C.mapMaybe (preview _Left) .| C.foldMap Set.singleton multiFileField' permittedFiles = multiFileField . runConduit $ permittedFiles .| C.mapMaybe (preview _Left) .| C.foldMap Set.singleton
multiFileField :: Handler (Set FileId) -- ^ Set of files that may be submitted by id-reference multiFileField :: Handler (Set FileId) -- ^ Set of files that may be submitted by id-reference
-> Field Handler (ConduitT () (Either FileId File) Handler ()) -> Field Handler FileUploads
multiFileField permittedFiles' = Field{..} multiFileField permittedFiles' = Field{..}
where where
fieldEnctype = Multipart fieldEnctype = Multipart
@ -746,7 +750,7 @@ multiFileField permittedFiles' = Field{..}
$(widgetFile "widgets/multiFileField") $(widgetFile "widgets/multiFileField")
unpackZips :: Text unpackZips :: Text
unpackZips = "unpack-zip" unpackZips = "unpack-zip"
takeLefts :: Monad m => ConduitM (Either b a) b m () takeLefts :: Monad m => ConduitT (Either b a) b m ()
takeLefts = awaitForever $ \case takeLefts = awaitForever $ \case
Right _ -> return () Right _ -> return ()
Left r -> yield r Left r -> yield r