Towards #364 for task 1
This commit is contained in:
parent
db915f5736
commit
7cda3e9f2e
@ -210,6 +210,7 @@ SubmissionFiles: Abgegebene Dateien
|
|||||||
SubmissionAlreadyExistsFor email@UserEmail: #{email} hat bereits eine Abgabe zu diesem Übungsblatt.
|
SubmissionAlreadyExistsFor email@UserEmail: #{email} hat bereits eine Abgabe zu diesem Übungsblatt.
|
||||||
SubmissionUsersEmpty: Es kann keine Abgabe ohne Abgebende erstellt werden
|
SubmissionUsersEmpty: Es kann keine Abgabe ohne Abgebende erstellt werden
|
||||||
SubmissionUserAlreadyAdded: Dieser Nutzer ist bereits als Mitabgebende(r) eingetragen
|
SubmissionUserAlreadyAdded: Dieser Nutzer ist bereits als Mitabgebende(r) eingetragen
|
||||||
|
NoOpenSubmissions: Keine unkorrigierten Abgaben vorhanden
|
||||||
|
|
||||||
SubmissionsDeleteQuestion n@Int: Wollen Sie #{pluralDE n "die unten aufgeführte Abgabe" "die unten aufgeführten Abgaben"} wirklich löschen?
|
SubmissionsDeleteQuestion n@Int: Wollen Sie #{pluralDE n "die unten aufgeführte Abgabe" "die unten aufgeführten Abgaben"} wirklich löschen?
|
||||||
SubmissionsDeleted n@Int: #{pluralDE n "Abgabe gelöscht" "Abgaben gelöscht"}
|
SubmissionsDeleted n@Int: #{pluralDE n "Abgabe gelöscht" "Abgaben gelöscht"}
|
||||||
@ -793,8 +794,9 @@ MenuSheetEdit: Übungsblatt editieren
|
|||||||
MenuSheetDelete: Übungsblatt löschen
|
MenuSheetDelete: Übungsblatt löschen
|
||||||
MenuSheetClone: Als neues Übungsblatt klonen
|
MenuSheetClone: Als neues Übungsblatt klonen
|
||||||
MenuCorrectionsUpload: Korrekturen hochladen
|
MenuCorrectionsUpload: Korrekturen hochladen
|
||||||
|
MenuCorrectionsDownload: Abgaben herunterladen
|
||||||
MenuCorrectionsCreate: Abgaben registrieren
|
MenuCorrectionsCreate: Abgaben registrieren
|
||||||
MenuCorrectionsGrade: Abgaben bewerten
|
MenuCorrectionsGrade: Abgaben online korrigieren
|
||||||
MenuAuthPreds: Authorisierungseinstellungen
|
MenuAuthPreds: Authorisierungseinstellungen
|
||||||
MenuTutorialDelete: Tutorium löschen
|
MenuTutorialDelete: Tutorium löschen
|
||||||
MenuTutorialEdit: Tutorium editieren
|
MenuTutorialEdit: Tutorium editieren
|
||||||
|
|||||||
@ -185,6 +185,7 @@ ghc-options:
|
|||||||
- -fno-warn-unrecognised-pragmas
|
- -fno-warn-unrecognised-pragmas
|
||||||
- -fno-warn-partial-type-signatures
|
- -fno-warn-partial-type-signatures
|
||||||
- -fno-max-relevant-binds
|
- -fno-max-relevant-binds
|
||||||
|
- -j2
|
||||||
|
|
||||||
when:
|
when:
|
||||||
- condition: flag(pedantic)
|
- condition: flag(pedantic)
|
||||||
|
|||||||
9
routes
9
routes
@ -137,10 +137,11 @@
|
|||||||
/tutor-invite TInviteR GET POST
|
/tutor-invite TInviteR GET POST
|
||||||
|
|
||||||
|
|
||||||
/subs CorrectionsR GET POST !corrector !lecturer
|
/subs CorrectionsR GET POST !corrector !lecturer
|
||||||
/subs/upload CorrectionsUploadR GET POST !corrector !lecturer
|
/subs/upload CorrectionsUploadR GET POST !corrector !lecturer
|
||||||
/subs/create CorrectionsCreateR GET POST !corrector !lecturer
|
/subs/create CorrectionsCreateR GET POST !corrector !lecturer
|
||||||
/subs/grade CorrectionsGradeR GET POST !corrector !lecturer
|
/subs/grade CorrectionsGradeR GET POST !corrector !lecturer
|
||||||
|
/subs/download CorrectionsDownloadR GET !corrector !lecturer
|
||||||
|
|
||||||
|
|
||||||
/msgs MessageListR GET POST
|
/msgs MessageListR GET POST
|
||||||
|
|||||||
@ -50,7 +50,8 @@ sqlInTuple arity = do
|
|||||||
]
|
]
|
||||||
|
|
||||||
-- | Generic unValuing of Tuples of Values, i.e.
|
-- | Generic unValuing of Tuples of Values, i.e.
|
||||||
-- $(unValueN 3) :: (E.Value a, E.Value b, E.Value c) -> (a,b,c)
|
--
|
||||||
|
-- > $(unValueN 3) :: (E.Value a, E.Value b, E.Value c) -> (a,b,c)
|
||||||
unValueN :: Int -> ExpQ
|
unValueN :: Int -> ExpQ
|
||||||
unValueN arity = do
|
unValueN arity = do
|
||||||
vs <- replicateM arity $ newName "v"
|
vs <- replicateM arity $ newName "v"
|
||||||
@ -60,7 +61,8 @@ unValueN arity = do
|
|||||||
lam1E pat rhs
|
lam1E pat rhs
|
||||||
|
|
||||||
-- | Generic unValuing of certain indices of a Tuple, i.e.
|
-- | Generic unValuing of certain indices of a Tuple, i.e.
|
||||||
-- $(unValueNIs 3 [1,3]) :: (E.Value a, b, E.Value c) -> (a,b,c)
|
--
|
||||||
|
-- > $(unValueNIs 3 [1,3]) :: (E.Value a, b, E.Value c) -> (a,b,c)
|
||||||
unValueNIs :: Int -> [Int] -> ExpQ
|
unValueNIs :: Int -> [Int] -> ExpQ
|
||||||
unValueNIs arity uvIdx = do
|
unValueNIs arity uvIdx = do
|
||||||
vs <- replicateM arity $ newName "v"
|
vs <- replicateM arity $ newName "v"
|
||||||
@ -74,8 +76,9 @@ unValueNIs arity uvIdx = do
|
|||||||
|
|
||||||
|
|
||||||
-- | Generic projections for InnerJoin-tuples
|
-- | Generic projections for InnerJoin-tuples
|
||||||
-- gives I-th element of N-tuple of left-associative InnerJoin-pairs,
|
-- gives I-th element of N-tuple of left-associative InnerJoin-pairs, i.e.
|
||||||
-- i.e. @$(projN n m) :: (t1 `E.InnerJoin` .. `E.InnerJoin` tn) -> tm@ (for m<=n)
|
--
|
||||||
|
-- > $(projN n m) :: (t1 `E.InnerJoin` .. `E.InnerJoin` tn) -> tm@ (for m<=n)
|
||||||
sqlIJproj :: Int -> Int -> ExpQ
|
sqlIJproj :: Int -> Int -> ExpQ
|
||||||
sqlIJproj = leftAssociativePairProjection 'E.InnerJoin
|
sqlIJproj = leftAssociativePairProjection 'E.InnerJoin
|
||||||
|
|
||||||
|
|||||||
@ -2231,6 +2231,14 @@ pageActions (CSheetR tid ssh csh shn SCorrR) =
|
|||||||
]
|
]
|
||||||
pageActions (CorrectionsR) =
|
pageActions (CorrectionsR) =
|
||||||
[ MenuItem
|
[ MenuItem
|
||||||
|
{ menuItemType = PageActionPrime
|
||||||
|
, menuItemLabel = MsgMenuCorrectionsDownload
|
||||||
|
, menuItemIcon = Nothing
|
||||||
|
, menuItemRoute = SomeRoute CorrectionsDownloadR
|
||||||
|
, menuItemModal = True
|
||||||
|
, menuItemAccessCallback' = return True
|
||||||
|
}
|
||||||
|
, MenuItem
|
||||||
{ menuItemType = PageActionPrime
|
{ menuItemType = PageActionPrime
|
||||||
, menuItemLabel = MsgMenuCorrectionsUpload
|
, menuItemLabel = MsgMenuCorrectionsUpload
|
||||||
, menuItemIcon = Nothing
|
, menuItemIcon = Nothing
|
||||||
|
|||||||
@ -502,7 +502,7 @@ postCorrectionsR = do
|
|||||||
let whereClause = ratedBy uid
|
let whereClause = ratedBy uid
|
||||||
colonnade = mconcat
|
colonnade = mconcat
|
||||||
[ colSelect
|
[ colSelect
|
||||||
, dbRow
|
-- , dbRow
|
||||||
, colSchool
|
, colSchool
|
||||||
, colTerm
|
, colTerm
|
||||||
, colCourse
|
, colCourse
|
||||||
|
|||||||
@ -600,3 +600,16 @@ postSubDelR tid ssh csh shn cID = do
|
|||||||
{ drAbort = SomeRoute $ CSubmissionR tid ssh csh shn cID SubShowR
|
{ drAbort = SomeRoute $ CSubmissionR tid ssh csh shn cID SubShowR
|
||||||
, drSuccess = SomeRoute $ CSheetR tid ssh csh shn SShowR
|
, drSuccess = SomeRoute $ CSheetR tid ssh csh shn SShowR
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
getCorrectionsDownloadR :: Handler TypedContent
|
||||||
|
getCorrectionsDownloadR = do -- download all assigned and open submissions
|
||||||
|
uid <- requireAuthId
|
||||||
|
subs <- runDB $ selectKeysList
|
||||||
|
[ SubmissionRatingBy ==. Just uid
|
||||||
|
, SubmissionRatingTime ==. Nothing
|
||||||
|
] []
|
||||||
|
when (null subs) $ do
|
||||||
|
addMessageI Info MsgNoOpenSubmissions
|
||||||
|
redirect CorrectionsR
|
||||||
|
submissionMultiArchive $ Set.fromList subs
|
||||||
@ -19,7 +19,7 @@ import Yesod.Core.Types (HandlerContents(..), ErrorResponse(..))
|
|||||||
import Utils.Lens
|
import Utils.Lens
|
||||||
|
|
||||||
import Control.Monad.State hiding (forM_, mapM_,foldM)
|
import Control.Monad.State hiding (forM_, mapM_,foldM)
|
||||||
import Control.Monad.Writer (MonadWriter(..), execWriterT)
|
import Control.Monad.Writer (MonadWriter(..), execWriterT, execWriter)
|
||||||
import Control.Monad.RWS.Lazy (RWST)
|
import Control.Monad.RWS.Lazy (RWST)
|
||||||
import qualified Control.Monad.Random as Rand
|
import qualified Control.Monad.Random as Rand
|
||||||
import qualified System.Random.Shuffle as Rand (shuffleM)
|
import qualified System.Random.Shuffle as Rand (shuffleM)
|
||||||
@ -43,6 +43,7 @@ import qualified Handler.Utils.Rating as Rating (extractRatings)
|
|||||||
import Handler.Utils.Delete
|
import Handler.Utils.Delete
|
||||||
|
|
||||||
import qualified Database.Esqueleto as E
|
import qualified Database.Esqueleto as E
|
||||||
|
import qualified Database.Esqueleto.Utils.TH as E
|
||||||
|
|
||||||
import qualified Data.Conduit.List as Conduit
|
import qualified Data.Conduit.List as Conduit
|
||||||
import Data.Conduit.ResumableSink
|
import Data.Conduit.ResumableSink
|
||||||
@ -223,17 +224,34 @@ submissionMultiArchive (Set.toList -> ids) = do
|
|||||||
(dbrunner, cleanup) <- getDBRunner
|
(dbrunner, cleanup) <- getDBRunner
|
||||||
|
|
||||||
ratedSubmissions <- runDBRunner dbrunner $ do
|
ratedSubmissions <- runDBRunner dbrunner $ do
|
||||||
submissions <- selectList [ SubmissionId <-. ids ] []
|
submissions <- E.select . E.from $ \(course `E.InnerJoin` sheet `E.InnerJoin` submission) -> do
|
||||||
forM submissions $ \s@(Entity submissionId _) -> maybe (invalidArgs ["Invalid submission numbers"]) (return . (, s)) =<< getRating submissionId
|
E.on $ sheet E.^. SheetId E.==. submission E.^. SubmissionSheet
|
||||||
|
E.on $ sheet E.^. SheetCourse E.==. course E.^. CourseId
|
||||||
|
E.where_ $ submission E.^. SubmissionId `E.in_` E.valList ids
|
||||||
|
return (submission, (sheet E.^. SheetName, course E.^. CourseShorthand, course E.^. CourseSchool, course E.^. CourseTerm))
|
||||||
|
|
||||||
|
forM submissions $ \(s@(Entity submissionId _), courseSheetInfo) ->
|
||||||
|
maybe (invalidArgs ["Invalid submission numbers"]) (return . (, s, $(E.unValueN 4) courseSheetInfo)) =<< getRating submissionId
|
||||||
|
let (setSheet,setCourse,setSchool,setTerm) =
|
||||||
|
execWriter . forM ratedSubmissions $ \(_rating,_submission,(shn,csh,ssh,tid)) ->
|
||||||
|
tell (Set.singleton shn, Set.singleton csh, Set.singleton ssh, Set.singleton tid)
|
||||||
|
|
||||||
(<* cleanup) . respondSource "application/zip" . transPipe (runDBRunner dbrunner) $ do
|
(<* cleanup) . respondSource "application/zip" . transPipe (runDBRunner dbrunner) $ do
|
||||||
let
|
let
|
||||||
fileEntitySource' :: (Rating, Entity Submission) -> Source (YesodDB UniWorX) File
|
fileEntitySource' :: (Rating, Entity Submission, (SheetName,CourseShorthand,SchoolId,TermId)) -> Source (YesodDB UniWorX) File
|
||||||
fileEntitySource' (rating, Entity submissionID Submission{..}) = do
|
fileEntitySource' (rating, Entity submissionID Submission{..},(shn,csh,ssh,tid)) = do
|
||||||
cID <- encrypt submissionID
|
cID <- encrypt submissionID
|
||||||
|
|
||||||
let
|
let
|
||||||
directoryName = Text.unpack $ toPathPiece (cID :: CryptoFileNameSubmission)
|
dirFrag :: PathPiece p => p -> FilePath
|
||||||
|
dirFrag = Text.unpack . toPathPiece
|
||||||
|
submissionDirectory = dirFrag (cID :: CryptoFileNameSubmission)
|
||||||
|
directoryName
|
||||||
|
| Set.size setTerm > 1 = dirFrag tid </> dirFrag ssh </> dirFrag csh </> dirFrag shn </> submissionDirectory
|
||||||
|
| Set.size setSchool > 1 = dirFrag ssh </> dirFrag csh </> dirFrag shn </> submissionDirectory
|
||||||
|
| Set.size setCourse > 1 = dirFrag csh </> dirFrag shn </> submissionDirectory
|
||||||
|
| Set.size setSheet > 1 = dirFrag shn </> submissionDirectory
|
||||||
|
| otherwise = submissionDirectory
|
||||||
|
|
||||||
fileEntitySource = do
|
fileEntitySource = do
|
||||||
submissionFileSource submissionID =$= Conduit.map entityVal
|
submissionFileSource submissionID =$= Conduit.map entityVal
|
||||||
|
|||||||
@ -3,7 +3,7 @@ module Utils.Sheet where
|
|||||||
import Import.NoFoundation
|
import Import.NoFoundation
|
||||||
import qualified Database.Esqueleto as E
|
import qualified Database.Esqueleto as E
|
||||||
|
|
||||||
import Database.Esqueleto.Internal.Language (From) -- How to avoid this import?
|
import Database.Esqueleto.Internal.Language (From) -- cannot be avoided here
|
||||||
|
|
||||||
-- DB Queries for Sheets that are used in several places
|
-- DB Queries for Sheets that are used in several places
|
||||||
|
|
||||||
@ -85,7 +85,6 @@ sheetFilesAllQuery tid ssh csh shn sft = E.select $ E.from $
|
|||||||
|
|
||||||
-- | Check whether a sheet has any files for a given file type
|
-- | Check whether a sheet has any files for a given file type
|
||||||
hasSheetFileQuery :: Database.Esqueleto.Internal.Language.From query expr backend (expr (Entity SheetFile))
|
hasSheetFileQuery :: Database.Esqueleto.Internal.Language.From query expr backend (expr (Entity SheetFile))
|
||||||
-- hasSheetFileQuery :: (E.Esqueleto query expr backend)
|
|
||||||
=> expr (Entity Sheet) -> SheetFileType -> expr (E.Value Bool)
|
=> expr (Entity Sheet) -> SheetFileType -> expr (E.Value Bool)
|
||||||
hasSheetFileQuery sheet sft =
|
hasSheetFileQuery sheet sft =
|
||||||
E.exists $ E.from $ \sFile ->
|
E.exists $ E.from $ \sFile ->
|
||||||
|
|||||||
6
templates/i18n/README_i18n.txt
Normal file
6
templates/i18n/README_i18n.txt
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
This directories contains all language dependent widgets.
|
||||||
|
|
||||||
|
Each widget requires its own directories, the name of which is needed in the source code, e.g. for directory "imprint"
|
||||||
|
$(i18nWidgetFile "imprint")
|
||||||
|
inside this directory must be one file per language "de.hamlet", etc.
|
||||||
|
|
||||||
Reference in New Issue
Block a user