Merge branch 'version-bumps' into 'master'
Version bumps to GHC 8.10.x See merge request uni2work/uni2work!20
This commit is contained in:
commit
a0412b073b
@ -96,7 +96,7 @@ sampleIntegral = sampleN scaleIntegral
|
|||||||
|
|
||||||
|
|
||||||
instance PathPiece DiffTime where
|
instance PathPiece DiffTime where
|
||||||
toPathPiece = toPathPiece . MkFixed @E12 . diffTimeToPicoseconds
|
toPathPiece = (toPathPiece :: Pico -> Text) . MkFixed . diffTimeToPicoseconds
|
||||||
fromPathPiece t = fromPathPiece t <&> \(MkFixed ps :: Pico) -> picosecondsToDiffTime ps
|
fromPathPiece t = fromPathPiece t <&> \(MkFixed ps :: Pico) -> picosecondsToDiffTime ps
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -253,7 +253,7 @@ executables:
|
|||||||
uniworx:
|
uniworx:
|
||||||
main: main.hs
|
main: main.hs
|
||||||
source-dirs: app
|
source-dirs: app
|
||||||
ghc-options: -threaded -rtsopts "-with-rtsopts=-N -T"
|
ghc-options: -threaded -rtsopts "-with-rtsopts=-N -T -xn"
|
||||||
dependencies:
|
dependencies:
|
||||||
- uniworx
|
- uniworx
|
||||||
when:
|
when:
|
||||||
@ -278,7 +278,7 @@ executables:
|
|||||||
ghc-options:
|
ghc-options:
|
||||||
- -main-is Load
|
- -main-is Load
|
||||||
- -threaded
|
- -threaded
|
||||||
- -rtsopts "-with-rtsopts=-N -T"
|
- -rtsopts "-with-rtsopts=-N -T -xn"
|
||||||
source-dirs: load
|
source-dirs: load
|
||||||
dependencies:
|
dependencies:
|
||||||
- uniworx
|
- uniworx
|
||||||
@ -313,8 +313,7 @@ tests:
|
|||||||
ghc-options:
|
ghc-options:
|
||||||
- -fno-warn-orphans
|
- -fno-warn-orphans
|
||||||
- -threaded
|
- -threaded
|
||||||
- -rtsopts
|
- -rtsopts "-with-rtsopts=-N -xn"
|
||||||
- -with-rtsopts=-N
|
|
||||||
hlint:
|
hlint:
|
||||||
main: Hlint.hs
|
main: Hlint.hs
|
||||||
other-modules: []
|
other-modules: []
|
||||||
|
|||||||
@ -94,13 +94,15 @@ import Handler.Utils.Routes (classifyHandler)
|
|||||||
|
|
||||||
import qualified Data.Acid.Memory as Acid
|
import qualified Data.Acid.Memory as Acid
|
||||||
import qualified Web.ServerSession.Backend.Acid as Acid
|
import qualified Web.ServerSession.Backend.Acid as Acid
|
||||||
|
|
||||||
import qualified Ldap.Client as Ldap (Host(Plain, Tls))
|
import qualified Ldap.Client as Ldap (Host(Plain, Tls))
|
||||||
|
|
||||||
import qualified Network.Minio as Minio
|
import qualified Network.Minio as Minio
|
||||||
|
|
||||||
import Web.ServerSession.Core (StorageException(..))
|
import Web.ServerSession.Core (StorageException(..))
|
||||||
|
|
||||||
|
import GHC.RTS.Flags (getRTSFlags)
|
||||||
|
|
||||||
-- Import all relevant handler modules here.
|
-- Import all relevant handler modules here.
|
||||||
-- (HPack takes care to add new modules to our cabal file nowadays.)
|
-- (HPack takes care to add new modules to our cabal file nowadays.)
|
||||||
import Handler.News
|
import Handler.News
|
||||||
@ -140,7 +142,7 @@ mkYesodDispatch "UniWorX" resourcesUniWorX
|
|||||||
makeFoundation :: (MonadResource m, MonadUnliftIO m, MonadCatch m) => AppSettings -> m UniWorX
|
makeFoundation :: (MonadResource m, MonadUnliftIO m, MonadCatch m) => AppSettings -> m UniWorX
|
||||||
makeFoundation appSettings'@AppSettings{..} = do
|
makeFoundation appSettings'@AppSettings{..} = do
|
||||||
registerGHCMetrics
|
registerGHCMetrics
|
||||||
|
|
||||||
-- Some basic initializations: HTTP connection manager, logger, and static
|
-- Some basic initializations: HTTP connection manager, logger, and static
|
||||||
-- subsite.
|
-- subsite.
|
||||||
appHttpManager <- newManager
|
appHttpManager <- newManager
|
||||||
@ -200,6 +202,7 @@ makeFoundation appSettings'@AppSettings{..} = do
|
|||||||
runAppLoggingT tempFoundation $ do
|
runAppLoggingT tempFoundation $ do
|
||||||
$logInfoS "InstanceID" $ UUID.toText appInstanceID
|
$logInfoS "InstanceID" $ UUID.toText appInstanceID
|
||||||
$logDebugS "Configuration" $ tshow appSettings'
|
$logDebugS "Configuration" $ tshow appSettings'
|
||||||
|
$logDebugS "RTSFlags" . tshow =<< liftIO getRTSFlags
|
||||||
|
|
||||||
smtpPool <- for appSmtpConf $ \c -> do
|
smtpPool <- for appSmtpConf $ \c -> do
|
||||||
$logDebugS "setup" "SMTP-Pool"
|
$logDebugS "setup" "SMTP-Pool"
|
||||||
@ -353,7 +356,7 @@ makeApplication foundation = liftIO $ makeMiddleware foundation <*> toWaiAppPlai
|
|||||||
makeMiddleware :: MonadIO m => UniWorX -> m Middleware
|
makeMiddleware :: MonadIO m => UniWorX -> m Middleware
|
||||||
makeMiddleware app = do
|
makeMiddleware app = do
|
||||||
logWare <- makeLogWare
|
logWare <- makeLogWare
|
||||||
return $ observeHTTPRequestLatency classifyHandler . logWare . normalizeCookies . defaultMiddlewaresNoLogging
|
return $ observeHTTPRequestLatency classifyHandler . logWare . normalizeCookies . defaultMiddlewaresNoLogging
|
||||||
where
|
where
|
||||||
makeLogWare = do
|
makeLogWare = do
|
||||||
logWareMap <- liftIO $ newTVarIO HashMap.empty
|
logWareMap <- liftIO $ newTVarIO HashMap.empty
|
||||||
@ -388,7 +391,7 @@ makeMiddleware app = do
|
|||||||
respond $ Wai.mapResponseHeaders (const resHdrs') res
|
respond $ Wai.mapResponseHeaders (const resHdrs') res
|
||||||
where parseSetCookie' :: ByteString -> IO (Maybe SetCookie)
|
where parseSetCookie' :: ByteString -> IO (Maybe SetCookie)
|
||||||
parseSetCookie' = fmap (either (\(_ :: SomeException) -> Nothing) Just) . try . evaluate . force . parseSetCookie
|
parseSetCookie' = fmap (either (\(_ :: SomeException) -> Nothing) Just) . try . evaluate . force . parseSetCookie
|
||||||
|
|
||||||
go [] = return []
|
go [] = return []
|
||||||
go (hdr@(hdrName, hdrValue) : hdrs)
|
go (hdr@(hdrName, hdrValue) : hdrs)
|
||||||
| hdrName == hSetCookie = do
|
| hdrName == hSetCookie = do
|
||||||
@ -455,7 +458,7 @@ warpSettings foundation = defaultSettings
|
|||||||
Just (SessionDoesNotExist{} :: StorageException (AcidStorage SessionMap)) -> False
|
Just (SessionDoesNotExist{} :: StorageException (AcidStorage SessionMap)) -> False
|
||||||
_other -> True
|
_other -> True
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
getAppDevSettings, getAppSettings :: MonadIO m => m AppSettings
|
getAppDevSettings, getAppSettings :: MonadIO m => m AppSettings
|
||||||
getAppDevSettings = liftIO $ loadYamlSettings [configSettingsYml] [configSettingsYmlValue] useEnv
|
getAppDevSettings = liftIO $ loadYamlSettings [configSettingsYml] [configSettingsYmlValue] useEnv
|
||||||
@ -476,7 +479,7 @@ develMain = runResourceT $ do
|
|||||||
lift $ threadDelay 100e3
|
lift $ threadDelay 100e3
|
||||||
whenM (lift $ doesFileExist "yesod-devel/devel-terminate") $
|
whenM (lift $ doesFileExist "yesod-devel/devel-terminate") $
|
||||||
callCC ($ ())
|
callCC ($ ())
|
||||||
|
|
||||||
void . liftIO $ installHandler sigINT (Signals.Catch $ return ()) Nothing
|
void . liftIO $ installHandler sigINT (Signals.Catch $ return ()) Nothing
|
||||||
runAppLoggingT foundation $ handleJobs foundation
|
runAppLoggingT foundation $ handleJobs foundation
|
||||||
void . liftIO $ awaitTermination `race` runSettings wsettings app
|
void . liftIO $ awaitTermination `race` runSettings wsettings app
|
||||||
|
|||||||
@ -54,7 +54,7 @@ getRemote = handle testHandler $ do
|
|||||||
guard $ h `elem` ["x-real-ip", "x-forwarded-for"]
|
guard $ h `elem` ["x-real-ip", "x-forwarded-for"]
|
||||||
v' <- either (const mzero) return $ Text.decodeUtf8' v
|
v' <- either (const mzero) return $ Text.decodeUtf8' v
|
||||||
maybeToList $ IP.decode v'
|
maybeToList $ IP.decode v'
|
||||||
|
|
||||||
byRemoteHost wai = case Wai.remoteHost wai of
|
byRemoteHost wai = case Wai.remoteHost wai of
|
||||||
Wai.SockAddrInet _ hAddr
|
Wai.SockAddrInet _ hAddr
|
||||||
-> let (b1, b2, b3, b4) = Wai.hostAddressToTuple hAddr
|
-> let (b1, b2, b3, b4) = Wai.hostAddressToTuple hAddr
|
||||||
|
|||||||
@ -23,7 +23,7 @@ data Transaction
|
|||||||
{ transactionExam :: ExamId
|
{ transactionExam :: ExamId
|
||||||
, transactionUser :: UserId
|
, transactionUser :: UserId
|
||||||
}
|
}
|
||||||
|
|
||||||
| TransactionExamPartResultEdit
|
| TransactionExamPartResultEdit
|
||||||
{ transactionExamPart :: ExamPartId
|
{ transactionExamPart :: ExamPartId
|
||||||
, transactionUser :: UserId
|
, transactionUser :: UserId
|
||||||
@ -88,7 +88,7 @@ data Transaction
|
|||||||
{ transactionSubmission :: SubmissionId
|
{ transactionSubmission :: SubmissionId
|
||||||
, transactionUser :: UserId
|
, transactionUser :: UserId
|
||||||
}
|
}
|
||||||
|
|
||||||
| TransactionSubmissionFileEdit
|
| TransactionSubmissionFileEdit
|
||||||
{ transactionSubmissionFile :: SubmissionFileId
|
{ transactionSubmissionFile :: SubmissionFileId
|
||||||
, transactionSubmission :: SubmissionId
|
, transactionSubmission :: SubmissionId
|
||||||
@ -133,7 +133,7 @@ data Transaction
|
|||||||
{ transactionExternalExam :: ExternalExamId
|
{ transactionExternalExam :: ExternalExamId
|
||||||
, transactionSchool :: SchoolId
|
, transactionSchool :: SchoolId
|
||||||
}
|
}
|
||||||
|
|
||||||
| TransactionExternalExamStaffEdit
|
| TransactionExternalExamStaffEdit
|
||||||
{ transactionExternalExam :: ExternalExamId
|
{ transactionExternalExam :: ExternalExamId
|
||||||
, transactionUser :: UserId
|
, transactionUser :: UserId
|
||||||
|
|||||||
@ -45,7 +45,7 @@ dummyLogin = AuthPlugin{..}
|
|||||||
where
|
where
|
||||||
apName :: Text
|
apName :: Text
|
||||||
apName = "dummy"
|
apName = "dummy"
|
||||||
|
|
||||||
apDispatch :: forall m. MonadAuthHandler site m => Text -> [Text] -> m TypedContent
|
apDispatch :: forall m. MonadAuthHandler site m => Text -> [Text] -> m TypedContent
|
||||||
apDispatch method [] | encodeUtf8 method == methodPost = liftSubHandler $ do
|
apDispatch method [] | encodeUtf8 method == methodPost = liftSubHandler $ do
|
||||||
((loginRes, _), _) <- runFormPost $ renderWForm FormStandard dummyForm
|
((loginRes, _), _) <- runFormPost $ renderWForm FormStandard dummyForm
|
||||||
@ -62,7 +62,7 @@ dummyLogin = AuthPlugin{..}
|
|||||||
setCredsRedirect $ Creds apName (CI.original ident) []
|
setCredsRedirect $ Creds apName (CI.original ident) []
|
||||||
apDispatch _ [] = badMethod
|
apDispatch _ [] = badMethod
|
||||||
apDispatch _ _ = notFound
|
apDispatch _ _ = notFound
|
||||||
|
|
||||||
apLogin :: (Route Auth -> Route site) -> WidgetFor site ()
|
apLogin :: (Route Auth -> Route site) -> WidgetFor site ()
|
||||||
apLogin toMaster = do
|
apLogin toMaster = do
|
||||||
(login, loginEnctype) <- handlerToWidget . generateFormPost $ renderWForm FormStandard dummyForm
|
(login, loginEnctype) <- handlerToWidget . generateFormPost $ renderWForm FormStandard dummyForm
|
||||||
|
|||||||
@ -52,7 +52,7 @@ findUser conf@LdapConf{..} ldap ident retAttrs = fromMaybe [] <$> findM (assertM
|
|||||||
[ ldapUserDisplayName Ldap.:= Text.encodeUtf8 ident
|
[ ldapUserDisplayName Ldap.:= Text.encodeUtf8 ident
|
||||||
, ldapUserMatriculation Ldap.:= Text.encodeUtf8 ident
|
, ldapUserMatriculation Ldap.:= Text.encodeUtf8 ident
|
||||||
]
|
]
|
||||||
|
|
||||||
findUserMatr :: LdapConf -> Ldap -> Text -> [Ldap.Attr] -> IO [Ldap.SearchEntry]
|
findUserMatr :: LdapConf -> Ldap -> Text -> [Ldap.Attr] -> IO [Ldap.SearchEntry]
|
||||||
findUserMatr conf@LdapConf{..} ldap userMatr retAttrs = fromMaybe [] <$> findM (assertM (not . null) . lift . flip (Ldap.search ldap ldapBase $ userSearchSettings conf) retAttrs) userFilters
|
findUserMatr conf@LdapConf{..} ldap userMatr retAttrs = fromMaybe [] <$> findM (assertM (not . null) . lift . flip (Ldap.search ldap ldapBase $ userSearchSettings conf) retAttrs) userFilters
|
||||||
where
|
where
|
||||||
@ -76,8 +76,8 @@ ldapUserFirstName = Ldap.Attr "givenName"
|
|||||||
ldapUserSurname = Ldap.Attr "sn"
|
ldapUserSurname = Ldap.Attr "sn"
|
||||||
ldapUserTitle = Ldap.Attr "title"
|
ldapUserTitle = Ldap.Attr "title"
|
||||||
ldapUserStudyFeatures = Ldap.Attr "dfnEduPersonFeaturesOfStudy"
|
ldapUserStudyFeatures = Ldap.Attr "dfnEduPersonFeaturesOfStudy"
|
||||||
ldapUserFieldName = Ldap.Attr "LMU-Stg-Fach"
|
ldapUserFieldName = Ldap.Attr "LMU-Stg-Fach"
|
||||||
ldapUserSchoolAssociation = Ldap.Attr "LMU-IFI-eduPersonOrgUnitDNString"
|
ldapUserSchoolAssociation = Ldap.Attr "LMU-IFI-eduPersonOrgUnitDNString"
|
||||||
ldapSex = Ldap.Attr "schacGender"
|
ldapSex = Ldap.Attr "schacGender"
|
||||||
ldapUserSubTermsSemester = Ldap.Attr "LMU-Stg-FachundFS"
|
ldapUserSubTermsSemester = Ldap.Attr "LMU-Stg-FachundFS"
|
||||||
|
|
||||||
@ -145,7 +145,7 @@ campusUserMatr pool mode userMatr = either (throwM . CampusUserLdapError) return
|
|||||||
[] -> throwM CampusUserNoResult
|
[] -> throwM CampusUserNoResult
|
||||||
[Ldap.SearchEntry _ attrs] -> return attrs
|
[Ldap.SearchEntry _ attrs] -> return attrs
|
||||||
_otherwise -> throwM CampusUserAmbiguous
|
_otherwise -> throwM CampusUserAmbiguous
|
||||||
|
|
||||||
campusUserMatr' :: (MonadMask m, MonadUnliftIO m, MonadLogger m) => Failover (LdapConf, LdapPool) -> FailoverMode -> UserMatriculation -> m (Maybe (Ldap.AttrList []))
|
campusUserMatr' :: (MonadMask m, MonadUnliftIO m, MonadLogger m) => Failover (LdapConf, LdapPool) -> FailoverMode -> UserMatriculation -> m (Maybe (Ldap.AttrList []))
|
||||||
campusUserMatr' pool mode
|
campusUserMatr' pool mode
|
||||||
= runMaybeT . catchIfMaybeT (is _CampusUserNoResult) . campusUserMatr pool mode
|
= runMaybeT . catchIfMaybeT (is _CampusUserNoResult) . campusUserMatr pool mode
|
||||||
@ -177,7 +177,7 @@ campusLogin pool mode = AuthPlugin{..}
|
|||||||
where
|
where
|
||||||
apName :: Text
|
apName :: Text
|
||||||
apName = apLdap
|
apName = apLdap
|
||||||
|
|
||||||
apDispatch :: forall m. MonadAuthHandler site m => Text -> [Text] -> m TypedContent
|
apDispatch :: forall m. MonadAuthHandler site m => Text -> [Text] -> m TypedContent
|
||||||
apDispatch method [] | encodeUtf8 method == methodPost = liftSubHandler $ do
|
apDispatch method [] | encodeUtf8 method == methodPost = liftSubHandler $ do
|
||||||
((loginRes, _), _) <- runFormPost $ renderWForm FormStandard campusForm
|
((loginRes, _), _) <- runFormPost $ renderWForm FormStandard campusForm
|
||||||
|
|||||||
@ -16,7 +16,7 @@ instance MonadResource m => MonadResource (StateCache c m) where
|
|||||||
|
|
||||||
instance MonadLogger m => MonadLogger (StateCache c m)
|
instance MonadLogger m => MonadLogger (StateCache c m)
|
||||||
instance MonadLoggerIO m => MonadLoggerIO (StateCache c m)
|
instance MonadLoggerIO m => MonadLoggerIO (StateCache c m)
|
||||||
|
|
||||||
instance MonadHandler m => MonadHandler (StateCache c m) where
|
instance MonadHandler m => MonadHandler (StateCache c m) where
|
||||||
type HandlerSite (StateCache c m) = HandlerSite m
|
type HandlerSite (StateCache c m) = HandlerSite m
|
||||||
type SubHandlerSite (StateCache c m) = SubHandlerSite m
|
type SubHandlerSite (StateCache c m) = SubHandlerSite m
|
||||||
|
|||||||
@ -21,7 +21,7 @@ import qualified Data.Set as Set
|
|||||||
|
|
||||||
import Utils.Lens hiding (from, to)
|
import Utils.Lens hiding (from, to)
|
||||||
|
|
||||||
|
|
||||||
data CronDate = CronDate
|
data CronDate = CronDate
|
||||||
{ cdYear, cdWeekYear, cdWeekOfYear, cdDayOfYear
|
{ cdYear, cdWeekYear, cdWeekOfYear, cdDayOfYear
|
||||||
, cdMonth, cdWeekOfMonth, cdDayOfMonth
|
, cdMonth, cdWeekOfMonth, cdDayOfMonth
|
||||||
@ -101,7 +101,7 @@ instance Alternative CronNextMatch where
|
|||||||
_ <|> MatchAsap = MatchAsap
|
_ <|> MatchAsap = MatchAsap
|
||||||
MatchAsap <|> _ = MatchAsap
|
MatchAsap <|> _ = MatchAsap
|
||||||
(MatchAt a) <|> (MatchAt _) = MatchAt a
|
(MatchAt a) <|> (MatchAt _) = MatchAt a
|
||||||
|
|
||||||
|
|
||||||
listToMatch :: [a] -> CronNextMatch a
|
listToMatch :: [a] -> CronNextMatch a
|
||||||
listToMatch [] = MatchNone
|
listToMatch [] = MatchNone
|
||||||
@ -203,7 +203,7 @@ nextCronMatch tz mPrev prec now c@Cron{..} = onlyOnceWithinPrec $ case notAfter
|
|||||||
in case execRef now False cronInitial of
|
in case execRef now False cronInitial of
|
||||||
MatchAsap
|
MatchAsap
|
||||||
| now < cutoffTime -> MatchAt cutoffTime
|
| now < cutoffTime -> MatchAt cutoffTime
|
||||||
MatchAt ts
|
MatchAt ts
|
||||||
| ts < cutoffTime -> MatchAt cutoffTime
|
| ts < cutoffTime -> MatchAt cutoffTime
|
||||||
other -> other
|
other -> other
|
||||||
CronRepeatScheduled cronNext
|
CronRepeatScheduled cronNext
|
||||||
|
|||||||
@ -11,12 +11,12 @@ import ClassyPrelude
|
|||||||
|
|
||||||
import Utils.Lens.TH
|
import Utils.Lens.TH
|
||||||
|
|
||||||
import Data.Time
|
import Data.Time
|
||||||
|
|
||||||
import Numeric.Natural
|
import Numeric.Natural
|
||||||
|
|
||||||
import qualified Data.Set as Set
|
import qualified Data.Set as Set
|
||||||
|
|
||||||
|
|
||||||
data CronMatch
|
data CronMatch
|
||||||
= CronMatchAny
|
= CronMatchAny
|
||||||
|
|||||||
@ -26,7 +26,7 @@ instance HashAlgorithm hash => PersistField (Digest hash) where
|
|||||||
fromPersistValue _ = Left "Digest values must be converted from PersistByteString or PersistText"
|
fromPersistValue _ = Left "Digest values must be converted from PersistByteString or PersistText"
|
||||||
|
|
||||||
instance HashAlgorithm hash => PersistFieldSql (Digest hash) where
|
instance HashAlgorithm hash => PersistFieldSql (Digest hash) where
|
||||||
sqlType _ = SqlBlob
|
sqlType _ = SqlBlob
|
||||||
|
|
||||||
instance HashAlgorithm hash => PathPiece (Digest hash) where
|
instance HashAlgorithm hash => PathPiece (Digest hash) where
|
||||||
toPathPiece = showToPathPiece
|
toPathPiece = showToPathPiece
|
||||||
|
|||||||
@ -38,7 +38,7 @@ encrypt :: forall plaintext ciphertext m.
|
|||||||
, Typeable ciphertext
|
, Typeable ciphertext
|
||||||
, PathPiece plaintext
|
, PathPiece plaintext
|
||||||
)
|
)
|
||||||
=> plaintext -> m (I.CryptoID ciphertext plaintext)
|
=> plaintext -> m (I.CryptoID ciphertext plaintext)
|
||||||
encrypt plain = $cachedHereBinary (toPathPiece plain) $ I.encrypt plain
|
encrypt plain = $cachedHereBinary (toPathPiece plain) $ I.encrypt plain
|
||||||
|
|
||||||
decrypt :: forall plaintext ciphertext m.
|
decrypt :: forall plaintext ciphertext m.
|
||||||
@ -47,7 +47,7 @@ decrypt :: forall plaintext ciphertext m.
|
|||||||
, Typeable plaintext
|
, Typeable plaintext
|
||||||
, PathPiece ciphertext
|
, PathPiece ciphertext
|
||||||
)
|
)
|
||||||
=> I.CryptoID ciphertext plaintext -> m plaintext
|
=> I.CryptoID ciphertext plaintext -> m plaintext
|
||||||
decrypt cipher = $cachedHereBinary (toPathPiece $ ciphertext cipher) $ I.decrypt cipher
|
decrypt cipher = $cachedHereBinary (toPathPiece $ ciphertext cipher) $ I.decrypt cipher
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -38,7 +38,7 @@ instance PersistField (CI String) where
|
|||||||
toPersistValue ciText = PersistDbSpecific . Text.encodeUtf8 . pack $ CI.original ciText
|
toPersistValue ciText = PersistDbSpecific . Text.encodeUtf8 . pack $ CI.original ciText
|
||||||
fromPersistValue (PersistDbSpecific bs) = Right . CI.mk . unpack $ Text.decodeUtf8 bs
|
fromPersistValue (PersistDbSpecific bs) = Right . CI.mk . unpack $ Text.decodeUtf8 bs
|
||||||
fromPersistValue x = Left . pack $ "Expected PersistDbSpecific, received: " ++ show x
|
fromPersistValue x = Left . pack $ "Expected PersistDbSpecific, received: " ++ show x
|
||||||
|
|
||||||
instance PersistFieldSql (CI Text) where
|
instance PersistFieldSql (CI Text) where
|
||||||
sqlType _ = SqlOther "citext"
|
sqlType _ = SqlOther "citext"
|
||||||
|
|
||||||
@ -77,8 +77,8 @@ instance ToWidget site a => ToWidget site (CI a) where
|
|||||||
instance RenderMessage site a => RenderMessage site (CI a) where
|
instance RenderMessage site a => RenderMessage site (CI a) where
|
||||||
renderMessage f ls msg = renderMessage f ls $ CI.original msg
|
renderMessage f ls msg = renderMessage f ls $ CI.original msg
|
||||||
|
|
||||||
instance Lift t => Lift (CI t) where
|
instance (CI.FoldCase t, Lift t) => Lift (CI t) where
|
||||||
lift (CI.original -> orig) = [e|CI.mk $(lift orig)|]
|
liftTyped (CI.original -> orig) = [||CI.mk $$(liftTyped orig)||]
|
||||||
|
|
||||||
|
|
||||||
instance (CI.FoldCase s, PathPiece s) => PathPiece (CI s) where
|
instance (CI.FoldCase s, PathPiece s) => PathPiece (CI s) where
|
||||||
|
|||||||
@ -16,7 +16,7 @@ import Data.Proxy (Proxy(..))
|
|||||||
|
|
||||||
import Data.Scientific
|
import Data.Scientific
|
||||||
import Data.Scientific.Instances ()
|
import Data.Scientific.Instances ()
|
||||||
|
|
||||||
|
|
||||||
instance HasResolution a => ToMarkup (Fixed a) where
|
instance HasResolution a => ToMarkup (Fixed a) where
|
||||||
toMarkup = toMarkup . showFixed True
|
toMarkup = toMarkup . showFixed True
|
||||||
|
|||||||
@ -10,4 +10,4 @@ import Text.Blaze (ToMarkup(..), string)
|
|||||||
|
|
||||||
instance ToMarkup a => ToMarkup (Maybe a) where
|
instance ToMarkup a => ToMarkup (Maybe a) where
|
||||||
toMarkup Nothing = string ""
|
toMarkup Nothing = string ""
|
||||||
toMarkup (Just x) = toMarkup x
|
toMarkup (Just x) = toMarkup x
|
||||||
|
|||||||
@ -19,7 +19,7 @@ instance MonoFunctor All where
|
|||||||
|
|
||||||
instance MonoPointed Any where
|
instance MonoPointed Any where
|
||||||
opoint = Any
|
opoint = Any
|
||||||
|
|
||||||
instance MonoPointed All where
|
instance MonoPointed All where
|
||||||
opoint = All
|
opoint = All
|
||||||
|
|
||||||
|
|||||||
@ -11,5 +11,5 @@ import Web.PathPieces
|
|||||||
|
|
||||||
|
|
||||||
instance PathPiece Scientific where
|
instance PathPiece Scientific where
|
||||||
toPathPiece = pack . formatScientific Fixed Nothing
|
toPathPiece = pack . formatScientific Fixed Nothing
|
||||||
fromPathPiece = readFromPathPiece
|
fromPathPiece = readFromPathPiece
|
||||||
|
|||||||
@ -10,4 +10,4 @@ import Data.Monoid (Sum(..))
|
|||||||
import Text.Blaze (ToMarkup(..))
|
import Text.Blaze (ToMarkup(..))
|
||||||
|
|
||||||
instance ToMarkup a => ToMarkup (Sum a) where
|
instance ToMarkup a => ToMarkup (Sum a) where
|
||||||
toMarkup = toMarkup . getSum
|
toMarkup = toMarkup . getSum
|
||||||
|
|||||||
@ -10,7 +10,7 @@ import qualified Data.UUID as UUID
|
|||||||
import Database.Persist.Sql
|
import Database.Persist.Sql
|
||||||
|
|
||||||
import Text.Blaze (ToMarkup(..))
|
import Text.Blaze (ToMarkup(..))
|
||||||
|
|
||||||
|
|
||||||
instance PathPiece UUID where
|
instance PathPiece UUID where
|
||||||
fromPathPiece = UUID.fromString . unpack
|
fromPathPiece = UUID.fromString . unpack
|
||||||
|
|||||||
@ -7,11 +7,11 @@ module Data.Universe.Instances.Reverse.MonoTraversable
|
|||||||
import Data.Universe
|
import Data.Universe
|
||||||
import Data.MonoTraversable
|
import Data.MonoTraversable
|
||||||
|
|
||||||
import Data.Universe.Instances.Reverse
|
import Data.Universe.Instances.Reverse
|
||||||
|
|
||||||
|
|
||||||
type instance Element (a -> b) = b
|
type instance Element (a -> b) = b
|
||||||
|
|
||||||
instance Finite a => MonoFoldable (a -> b)
|
instance Finite a => MonoFoldable (a -> b)
|
||||||
instance (Ord a, Finite a) => MonoTraversable (a -> b)
|
instance (Ord a, Finite a) => MonoTraversable (a -> b)
|
||||||
|
|
||||||
|
|||||||
@ -23,7 +23,7 @@ import Data.List (elemIndex)
|
|||||||
getTVBName :: TyVarBndr -> Name
|
getTVBName :: TyVarBndr -> Name
|
||||||
getTVBName (PlainTV name ) = name
|
getTVBName (PlainTV name ) = name
|
||||||
getTVBName (KindedTV name _) = name
|
getTVBName (KindedTV name _) = name
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
finiteEnum :: Name -> DecsQ
|
finiteEnum :: Name -> DecsQ
|
||||||
@ -33,7 +33,7 @@ finiteEnum tName = do
|
|||||||
|
|
||||||
let datatype = foldl appT (conT datatypeName) $ map (varT . getTVBName) datatypeVars
|
let datatype = foldl appT (conT datatypeName) $ map (varT . getTVBName) datatypeVars
|
||||||
tUniverse = [e|universeF :: [$(datatype)]|]
|
tUniverse = [e|universeF :: [$(datatype)]|]
|
||||||
|
|
||||||
[d|
|
[d|
|
||||||
instance Bounded $(datatype) where
|
instance Bounded $(datatype) where
|
||||||
minBound = head $(tUniverse)
|
minBound = head $(tUniverse)
|
||||||
|
|||||||
@ -196,7 +196,7 @@ orderByList :: PersistField a => [a] -> E.SqlExpr (E.Value a) -> E.SqlExpr (E.Va
|
|||||||
orderByList vals
|
orderByList vals
|
||||||
= let sortUni = zip [1..] vals -- memoize this, might not work due to polymorphism
|
= let sortUni = zip [1..] vals -- memoize this, might not work due to polymorphism
|
||||||
in \x -> E.case_ [ (x E.==. E.val u, E.val i) | (i,u) <- sortUni ] (E.val . succ $ List.length vals)
|
in \x -> E.case_ [ (x E.==. E.val u, E.val i) | (i,u) <- sortUni ] (E.val . succ $ List.length vals)
|
||||||
|
|
||||||
orderByOrd :: (Ord a, Finite a, PersistField a) => E.SqlExpr (E.Value a) -> E.SqlExpr (E.Value Int)
|
orderByOrd :: (Ord a, Finite a, PersistField a) => E.SqlExpr (E.Value a) -> E.SqlExpr (E.Value Int)
|
||||||
orderByOrd = orderByList $ List.sort universeF
|
orderByOrd = orderByList $ List.sort universeF
|
||||||
|
|
||||||
@ -206,12 +206,12 @@ orderByEnum = orderByList $ List.sortOn fromEnum universeF
|
|||||||
|
|
||||||
lower :: E.SqlString s => E.SqlExpr (E.Value s) -> E.SqlExpr (E.Value s)
|
lower :: E.SqlString s => E.SqlExpr (E.Value s) -> E.SqlExpr (E.Value s)
|
||||||
lower = E.unsafeSqlFunction "LOWER"
|
lower = E.unsafeSqlFunction "LOWER"
|
||||||
|
|
||||||
strip :: E.SqlString s => E.SqlExpr (E.Value s) -> E.SqlExpr (E.Value s)
|
strip :: E.SqlString s => E.SqlExpr (E.Value s) -> E.SqlExpr (E.Value s)
|
||||||
strip = E.unsafeSqlFunction "TRIM"
|
strip = E.unsafeSqlFunction "TRIM"
|
||||||
|
|
||||||
infix 4 `ciEq`
|
infix 4 `ciEq`
|
||||||
|
|
||||||
ciEq :: E.SqlString s => E.SqlExpr (E.Value s) -> E.SqlExpr (E.Value s) -> E.SqlExpr (E.Value Bool)
|
ciEq :: E.SqlString s => E.SqlExpr (E.Value s) -> E.SqlExpr (E.Value s) -> E.SqlExpr (E.Value Bool)
|
||||||
ciEq a b = lower a E.==. lower b
|
ciEq a b = lower a E.==. lower b
|
||||||
|
|
||||||
@ -249,7 +249,7 @@ maybe onNothing onJust val = E.case_
|
|||||||
(onJust $ E.veryUnsafeCoerceSqlExprValue val)
|
(onJust $ E.veryUnsafeCoerceSqlExprValue val)
|
||||||
]
|
]
|
||||||
(E.else_ onNothing)
|
(E.else_ onNothing)
|
||||||
|
|
||||||
infix 4 `maybeEq`
|
infix 4 `maybeEq`
|
||||||
|
|
||||||
maybeEq :: PersistField a
|
maybeEq :: PersistField a
|
||||||
|
|||||||
@ -46,7 +46,7 @@ sqlInTuple arity = do
|
|||||||
xsV <- newName "xs"
|
xsV <- newName "xs"
|
||||||
|
|
||||||
let
|
let
|
||||||
matchE = lam1E (tupP $ map (\vV -> conP 'E.Value [varP vV]) vVs) (foldr1 (\e1 e2 -> [e|$(e1) E.&&. $(e2)|]) . map (\(varE -> vE, varE -> xE) -> [e|E.val $(vE) `sqlEq` $(xE)|]) $ zip vVs xVs)
|
matchE = lam1E (tupP $ map (\vV -> conP 'E.Value [varP vV]) vVs) (foldr1 (\e1 e2 -> [e|$(e1) E.&&. $(e2)|]) $ zipWith (\(varE -> vE) (varE -> xE) -> [e|E.val $(vE) `sqlEq` $(xE)|]) vVs xVs)
|
||||||
tupTy f = foldl (\typ v -> typ `appT` f (varT v)) (tupleT arity) tyVars
|
tupTy f = foldl (\typ v -> typ `appT` f (varT v)) (tupleT arity) tyVars
|
||||||
|
|
||||||
instanceD (cxt $ map (\v -> [t|SqlEq $(varT v)|]) tyVars) [t|SqlIn $(tupTy $ \v -> [t|E.SqlExpr (E.Value $(v))|]) $(tupTy $ \v -> [t|E.Value $(v)|])|]
|
instanceD (cxt $ map (\v -> [t|SqlEq $(varT v)|]) tyVars) [t|SqlIn $(tupTy $ \v -> [t|E.SqlExpr (E.Value $(v))|]) $(tupTy $ \v -> [t|E.Value $(v)|])|]
|
||||||
|
|||||||
@ -18,13 +18,13 @@ import qualified System.Directory.Tree as DirTree
|
|||||||
import Control.Monad.Trans.Maybe (MaybeT(MaybeT), runMaybeT)
|
import Control.Monad.Trans.Maybe (MaybeT(MaybeT), runMaybeT)
|
||||||
|
|
||||||
import Control.Lens
|
import Control.Lens
|
||||||
|
|
||||||
|
|
||||||
persistDirectoryWith :: PersistSettings -> FilePath -> Q Exp
|
persistDirectoryWith :: PersistSettings -> FilePath -> Q Exp
|
||||||
persistDirectoryWith settings dir = do
|
persistDirectoryWith settings dir = do
|
||||||
files <- runIO . flip DirTree.readDirectoryWith dir $ \fp -> runMaybeT $ do
|
files <- runIO . flip DirTree.readDirectoryWith dir $ \fp -> runMaybeT $ do
|
||||||
fn <- MaybeT . return . fromNullable $ takeFileName fp
|
fn <- MaybeT . return . fromNullable $ takeFileName fp
|
||||||
guard . not $ head fn == '.'
|
guard $ head fn /= '.'
|
||||||
guard . not $ head fn == '#' && last fn == '#'
|
guard . not $ head fn == '#' && last fn == '#'
|
||||||
|
|
||||||
lift $ do
|
lift $ do
|
||||||
@ -32,5 +32,5 @@ persistDirectoryWith settings dir = do
|
|||||||
SIO.hSetEncoding h SIO.utf8_bom
|
SIO.hSetEncoding h SIO.utf8_bom
|
||||||
Text.hGetContents h
|
Text.hGetContents h
|
||||||
mapM_ qAddDependentFile . toListOf (traverse . filtered (has $ _2 . _Just) . _1) $ DirTree.zipPaths files
|
mapM_ qAddDependentFile . toListOf (traverse . filtered (has $ _2 . _Just) . _1) $ DirTree.zipPaths files
|
||||||
|
|
||||||
parseReferences settings . Text.intercalate "\n" . toListOf (traverse . _Just) $ DirTree.dirTree files
|
parseReferences settings . Text.intercalate "\n" . toListOf (traverse . _Just) $ DirTree.dirTree files
|
||||||
|
|||||||
@ -15,7 +15,8 @@ import Foundation.Routes as Foundation
|
|||||||
|
|
||||||
|
|
||||||
import Import.NoFoundation hiding (embedFile)
|
import Import.NoFoundation hiding (embedFile)
|
||||||
import Database.Persist.Sql (runSqlPool)
|
import Database.Persist.Sql
|
||||||
|
( runSqlPool, transactionUndo, SqlReadBackend(..) )
|
||||||
import Text.Hamlet (hamletFile)
|
import Text.Hamlet (hamletFile)
|
||||||
|
|
||||||
import Yesod.Auth.Message
|
import Yesod.Auth.Message
|
||||||
@ -106,7 +107,6 @@ import qualified Web.ServerSession.Frontend.Yesod.Jwt as JwtSession
|
|||||||
import Web.Cookie
|
import Web.Cookie
|
||||||
|
|
||||||
import Yesod.Core.Types (GHState(..), HandlerData(..), HandlerContents, RunHandlerEnv(rheSite, rheChild))
|
import Yesod.Core.Types (GHState(..), HandlerData(..), HandlerContents, RunHandlerEnv(rheSite, rheChild))
|
||||||
import Database.Persist.Sql (transactionUndo, SqlReadBackend(..))
|
|
||||||
|
|
||||||
import qualified Control.Retry as Retry
|
import qualified Control.Retry as Retry
|
||||||
import GHC.IO.Exception (IOErrorType(OtherError))
|
import GHC.IO.Exception (IOErrorType(OtherError))
|
||||||
@ -197,7 +197,7 @@ data Nav
|
|||||||
|
|
||||||
makeLenses_ ''Nav
|
makeLenses_ ''Nav
|
||||||
makePrisms ''Nav
|
makePrisms ''Nav
|
||||||
|
|
||||||
data NavChildren
|
data NavChildren
|
||||||
type instance Children NavChildren a = ChildrenNavChildren a
|
type instance Children NavChildren a = ChildrenNavChildren a
|
||||||
type family ChildrenNavChildren a where
|
type family ChildrenNavChildren a where
|
||||||
@ -218,13 +218,13 @@ navLinkAccess NavLink{..} = handle shortCircuit $ liftHandler navAccess' `and2M`
|
|||||||
where
|
where
|
||||||
shortCircuit :: HandlerContents -> m Bool
|
shortCircuit :: HandlerContents -> m Bool
|
||||||
shortCircuit _ = return False
|
shortCircuit _ = return False
|
||||||
|
|
||||||
accessCheck :: HasRoute UniWorX route => NavType -> route -> m Bool
|
accessCheck :: HasRoute UniWorX route => NavType -> route -> m Bool
|
||||||
accessCheck nt (urlRoute -> route) = do
|
accessCheck nt (urlRoute -> route) = do
|
||||||
authCtx <- getAuthContext
|
authCtx <- getAuthContext
|
||||||
$memcachedByHere (Just $ Right 120) (authCtx, nt, route) $
|
$memcachedByHere (Just $ Right 120) (authCtx, nt, route) $
|
||||||
bool hasWriteAccessTo hasReadAccessTo (is _NavTypeLink nt) route
|
bool hasWriteAccessTo hasReadAccessTo (is _NavTypeLink nt) route
|
||||||
|
|
||||||
|
|
||||||
getTimeLocale' :: [Lang] -> TimeLocale
|
getTimeLocale' :: [Lang] -> TimeLocale
|
||||||
getTimeLocale' = $(timeLocaleMap [("de-de", "de_DE.utf8"), ("en-GB", "en_GB.utf8")])
|
getTimeLocale' = $(timeLocaleMap [("de-de", "de_DE.utf8"), ("en-GB", "en_GB.utf8")])
|
||||||
@ -245,7 +245,7 @@ appLanguagesOpts = do
|
|||||||
}
|
}
|
||||||
langOptions = map mkOption $ toList appLanguages
|
langOptions = map mkOption $ toList appLanguages
|
||||||
return $ mkOptionList langOptions
|
return $ mkOptionList langOptions
|
||||||
|
|
||||||
instance RenderMessage UniWorX WeekDay where
|
instance RenderMessage UniWorX WeekDay where
|
||||||
renderMessage _ ls wDay = pack . fst $ wDays (getTimeLocale' ls) !! (fromEnum wDay `mod` 7)
|
renderMessage _ ls wDay = pack . fst $ wDays (getTimeLocale' ls) !! (fromEnum wDay `mod` 7)
|
||||||
|
|
||||||
@ -420,7 +420,7 @@ requireCurrentBearerRestrictions = runMaybeT $ do
|
|||||||
bearer <- requireBearerToken
|
bearer <- requireBearerToken
|
||||||
route <- MaybeT getCurrentRoute
|
route <- MaybeT getCurrentRoute
|
||||||
hoistMaybe $ bearer ^? _bearerRestrictionIx route
|
hoistMaybe $ bearer ^? _bearerRestrictionIx route
|
||||||
|
|
||||||
maybeCurrentBearerRestrictions :: forall a m.
|
maybeCurrentBearerRestrictions :: forall a m.
|
||||||
( MonadHandler m
|
( MonadHandler m
|
||||||
, HandlerSite m ~ UniWorX
|
, HandlerSite m ~ UniWorX
|
||||||
@ -451,7 +451,7 @@ isDryRun = $cachedHere $ orM
|
|||||||
mAuthId <- maybeAuthId
|
mAuthId <- maybeAuthId
|
||||||
currentRoute <- maybe (permissionDeniedI MsgUnauthorizedToken404) return =<< getCurrentRoute
|
currentRoute <- maybe (permissionDeniedI MsgUnauthorizedToken404) return =<< getCurrentRoute
|
||||||
isWrite <- isWriteRequest currentRoute
|
isWrite <- isWriteRequest currentRoute
|
||||||
|
|
||||||
let noTokenAuth :: AuthDNF -> AuthDNF
|
let noTokenAuth :: AuthDNF -> AuthDNF
|
||||||
noTokenAuth = over _dnfTerms . Set.filter . noneOf (re _nullable . folded) $ (== AuthToken) . plVar
|
noTokenAuth = over _dnfTerms . Set.filter . noneOf (re _nullable . folded) $ (== AuthToken) . plVar
|
||||||
|
|
||||||
@ -529,7 +529,7 @@ tagAccessPredicate AuthExamOffice = APDB $ \mAuthId route _ -> case route of
|
|||||||
E.&&. eexam E.^. ExternalExamSchool E.==. E.val ssh
|
E.&&. eexam E.^. ExternalExamSchool E.==. E.val ssh
|
||||||
E.&&. eexam E.^. ExternalExamCourseName E.==. E.val coursen
|
E.&&. eexam E.^. ExternalExamCourseName E.==. E.val coursen
|
||||||
E.&&. eexam E.^. ExternalExamExamName E.==. E.val examn
|
E.&&. eexam E.^. ExternalExamExamName E.==. E.val examn
|
||||||
|
|
||||||
E.where_ $ examOfficeExternalExamResultAuth (E.val authId) eexamResult
|
E.where_ $ examOfficeExternalExamResultAuth (E.val authId) eexamResult
|
||||||
guardMExceptT hasUsers $ unauthorizedI MsgUnauthorizedExternalExamExamOffice
|
guardMExceptT hasUsers $ unauthorizedI MsgUnauthorizedExternalExamExamOffice
|
||||||
return Authorized
|
return Authorized
|
||||||
@ -651,7 +651,7 @@ tagAccessPredicate AuthCorrector = APDB $ \mAuthId route _ -> exceptT return ret
|
|||||||
CSubmissionR _ _ _ _ cID _ -> $cachedHereBinary (mAuthId, cID) . maybeT (unauthorizedI MsgUnauthorizedSubmissionCorrector) $ do
|
CSubmissionR _ _ _ _ cID _ -> $cachedHereBinary (mAuthId, cID) . maybeT (unauthorizedI MsgUnauthorizedSubmissionCorrector) $ do
|
||||||
sid <- catchIfMaybeT (const True :: CryptoIDError -> Bool) $ decrypt cID
|
sid <- catchIfMaybeT (const True :: CryptoIDError -> Bool) $ decrypt cID
|
||||||
Submission{..} <- MaybeT . lift $ get sid
|
Submission{..} <- MaybeT . lift $ get sid
|
||||||
guard $ maybe False (== authId) submissionRatingBy
|
guard $ Just authId == submissionRatingBy
|
||||||
return Authorized
|
return Authorized
|
||||||
CSheetR tid ssh csh shn _ -> $cachedHereBinary (mAuthId, tid, ssh, csh, shn) . maybeT (unauthorizedI MsgUnauthorizedSheetCorrector) $ do
|
CSheetR tid ssh csh shn _ -> $cachedHereBinary (mAuthId, tid, ssh, csh, shn) . maybeT (unauthorizedI MsgUnauthorizedSheetCorrector) $ do
|
||||||
Entity cid _ <- MaybeT . lift . getBy $ TermSchoolCourseShort tid ssh csh
|
Entity cid _ <- MaybeT . lift . getBy $ TermSchoolCourseShort tid ssh csh
|
||||||
@ -742,24 +742,10 @@ tagAccessPredicate AuthSubmissionGroup = APDB $ \mAuthId route _ -> case route o
|
|||||||
E.on $ submissionGroupUser E.^. SubmissionGroupUserSubmissionGroup E.==. submissionGroup E.^. SubmissionGroupId
|
E.on $ submissionGroupUser E.^. SubmissionGroupUserSubmissionGroup E.==. submissionGroup E.^. SubmissionGroupId
|
||||||
E.where_ $ submissionGroup E.^. SubmissionGroupCourse E.==. E.val course
|
E.where_ $ submissionGroup E.^. SubmissionGroupCourse E.==. E.val course
|
||||||
E.&&. submissionGroupUser E.^. SubmissionGroupUserUser E.==. E.val uid
|
E.&&. submissionGroupUser E.^. SubmissionGroupUserUser E.==. E.val uid
|
||||||
|
|
||||||
return Authorized
|
return Authorized
|
||||||
r -> $unsupportedAuthPredicate AuthSubmissionGroup r
|
r -> $unsupportedAuthPredicate AuthSubmissionGroup r
|
||||||
tagAccessPredicate AuthTime = APDB $ \mAuthId route _ -> case route of
|
tagAccessPredicate AuthTime = APDB $ \mAuthId route _ -> case route of
|
||||||
CApplicationR tid ssh csh _ _ -> maybeT (unauthorizedI MsgUnauthorizedApplicationTime) $ do
|
|
||||||
course <- $cachedHereBinary (tid, ssh, csh) . MaybeT . getKeyBy $ TermSchoolCourseShort tid ssh csh
|
|
||||||
allocationCourse <- $cachedHereBinary course . lift . getBy $ UniqueAllocationCourse course
|
|
||||||
allocation <- for allocationCourse $ \(Entity _ AllocationCourse{..}) -> $cachedHereBinary allocationCourseAllocation . MaybeT $ get allocationCourseAllocation
|
|
||||||
|
|
||||||
case allocation of
|
|
||||||
Nothing -> return ()
|
|
||||||
Just Allocation{..} -> do
|
|
||||||
cTime <- liftIO getCurrentTime
|
|
||||||
guard $ NTop allocationStaffAllocationFrom <= NTop (Just cTime)
|
|
||||||
guard $ NTop (Just cTime) <= NTop allocationStaffAllocationTo
|
|
||||||
|
|
||||||
return Authorized
|
|
||||||
|
|
||||||
CExamR tid ssh csh examn subRoute -> maybeT (unauthorizedI MsgUnauthorizedExamTime) $ do
|
CExamR tid ssh csh examn subRoute -> maybeT (unauthorizedI MsgUnauthorizedExamTime) $ do
|
||||||
course <- $cachedHereBinary (tid, ssh, csh) . MaybeT . getKeyBy $ TermSchoolCourseShort tid ssh csh
|
course <- $cachedHereBinary (tid, ssh, csh) . MaybeT . getKeyBy $ TermSchoolCourseShort tid ssh csh
|
||||||
Entity eId Exam{..} <- $cachedHereBinary (course, examn) . MaybeT . getBy $ UniqueExam course examn
|
Entity eId Exam{..} <- $cachedHereBinary (course, examn) . MaybeT . getBy $ UniqueExam course examn
|
||||||
@ -783,7 +769,7 @@ tagAccessPredicate AuthTime = APDB $ \mAuthId route _ -> case route of
|
|||||||
-> guard $ visible
|
-> guard $ visible
|
||||||
&& NTop (Just cTime) <= NTop examDeregisterUntil
|
&& NTop (Just cTime) <= NTop examDeregisterUntil
|
||||||
ERegisterOccR occn -> do
|
ERegisterOccR occn -> do
|
||||||
occId <- (>>= hoistMaybe) . $cachedHereBinary (eId, occn) . lift . getKeyBy $ UniqueExamOccurrence eId occn
|
occId <- hoistMaybe <=< $cachedHereBinary (eId, occn) . lift . getKeyBy $ UniqueExamOccurrence eId occn
|
||||||
if
|
if
|
||||||
| (registration >>= examRegistrationOccurrence . entityVal) == Just occId
|
| (registration >>= examRegistrationOccurrence . entityVal) == Just occId
|
||||||
-> guard $ visible
|
-> guard $ visible
|
||||||
@ -920,7 +906,7 @@ tagAccessPredicate AuthTime = APDB $ \mAuthId route _ -> case route of
|
|||||||
MessageR cID -> maybeT (unauthorizedI MsgUnauthorizedSystemMessageTime) $ do
|
MessageR cID -> maybeT (unauthorizedI MsgUnauthorizedSystemMessageTime) $ do
|
||||||
smId <- catchIfMaybeT (const True :: CryptoIDError -> Bool) $ decrypt cID
|
smId <- catchIfMaybeT (const True :: CryptoIDError -> Bool) $ decrypt cID
|
||||||
SystemMessage{systemMessageFrom, systemMessageTo} <- $cachedHereBinary smId . MaybeT $ get smId
|
SystemMessage{systemMessageFrom, systemMessageTo} <- $cachedHereBinary smId . MaybeT $ get smId
|
||||||
cTime <- (NTop . Just) <$> liftIO getCurrentTime
|
cTime <- NTop . Just <$> liftIO getCurrentTime
|
||||||
guard $ NTop systemMessageFrom <= cTime
|
guard $ NTop systemMessageFrom <= cTime
|
||||||
&& NTop systemMessageTo >= cTime
|
&& NTop systemMessageTo >= cTime
|
||||||
return Authorized
|
return Authorized
|
||||||
@ -928,7 +914,7 @@ tagAccessPredicate AuthTime = APDB $ \mAuthId route _ -> case route of
|
|||||||
MessageHideR cID -> maybeT (unauthorizedI MsgUnauthorizedSystemMessageTime) $ do
|
MessageHideR cID -> maybeT (unauthorizedI MsgUnauthorizedSystemMessageTime) $ do
|
||||||
smId <- catchIfMaybeT (const True :: CryptoIDError -> Bool) $ decrypt cID
|
smId <- catchIfMaybeT (const True :: CryptoIDError -> Bool) $ decrypt cID
|
||||||
SystemMessage{systemMessageFrom, systemMessageTo} <- $cachedHereBinary smId . MaybeT $ get smId
|
SystemMessage{systemMessageFrom, systemMessageTo} <- $cachedHereBinary smId . MaybeT $ get smId
|
||||||
cTime <- (NTop . Just) <$> liftIO getCurrentTime
|
cTime <- NTop . Just <$> liftIO getCurrentTime
|
||||||
guard $ NTop systemMessageFrom <= cTime
|
guard $ NTop systemMessageFrom <= cTime
|
||||||
&& NTop systemMessageTo >= cTime
|
&& NTop systemMessageTo >= cTime
|
||||||
return Authorized
|
return Authorized
|
||||||
@ -936,7 +922,7 @@ tagAccessPredicate AuthTime = APDB $ \mAuthId route _ -> case route of
|
|||||||
CNewsR _ _ _ cID _ -> maybeT (unauthorizedI MsgUnauthorizedCourseNewsTime) $ do
|
CNewsR _ _ _ cID _ -> maybeT (unauthorizedI MsgUnauthorizedCourseNewsTime) $ do
|
||||||
nId <- catchIfMaybeT (const True :: CryptoIDError -> Bool) $ decrypt cID
|
nId <- catchIfMaybeT (const True :: CryptoIDError -> Bool) $ decrypt cID
|
||||||
CourseNews{courseNewsVisibleFrom} <- $cachedHereBinary nId . MaybeT $ get nId
|
CourseNews{courseNewsVisibleFrom} <- $cachedHereBinary nId . MaybeT $ get nId
|
||||||
cTime <- (NTop . Just) <$> liftIO getCurrentTime
|
cTime <- NTop . Just <$> liftIO getCurrentTime
|
||||||
guard $ NTop courseNewsVisibleFrom <= cTime
|
guard $ NTop courseNewsVisibleFrom <= cTime
|
||||||
return Authorized
|
return Authorized
|
||||||
|
|
||||||
@ -1247,7 +1233,7 @@ tagAccessPredicate AuthParticipant = APDB $ \mAuthId route _ -> case route of
|
|||||||
when onlyActive $
|
when onlyActive $
|
||||||
E.where_ $ courseParticipant E.^. CourseParticipantState E.==. E.val CourseParticipantActive
|
E.where_ $ courseParticipant E.^. CourseParticipantState E.==. E.val CourseParticipantActive
|
||||||
-- participant has at least one submission
|
-- participant has at least one submission
|
||||||
when (not onlyActive) $
|
unless onlyActive $
|
||||||
mapExceptT ($cachedHereBinary (participant, tid, ssh, csh)) . authorizedIfExists $ \(course `E.InnerJoin` sheet `E.InnerJoin` submission `E.InnerJoin` submissionUser) -> do
|
mapExceptT ($cachedHereBinary (participant, tid, ssh, csh)) . authorizedIfExists $ \(course `E.InnerJoin` sheet `E.InnerJoin` submission `E.InnerJoin` submissionUser) -> do
|
||||||
E.on $ submission E.^. SubmissionId E.==. submissionUser E.^. SubmissionUserSubmission
|
E.on $ submission E.^. SubmissionId E.==. submissionUser E.^. SubmissionUserSubmission
|
||||||
E.on $ sheet E.^. SheetId E.==. submission E.^. SubmissionSheet
|
E.on $ sheet E.^. SheetId E.==. submission E.^. SubmissionSheet
|
||||||
@ -1257,7 +1243,7 @@ tagAccessPredicate AuthParticipant = APDB $ \mAuthId route _ -> case route of
|
|||||||
E.&&. course E.^. CourseSchool E.==. E.val ssh
|
E.&&. course E.^. CourseSchool E.==. E.val ssh
|
||||||
E.&&. course E.^. CourseShorthand E.==. E.val csh
|
E.&&. course E.^. CourseShorthand E.==. E.val csh
|
||||||
-- participant is member of a submissionGroup
|
-- participant is member of a submissionGroup
|
||||||
when (not onlyActive) $
|
unless onlyActive $
|
||||||
mapExceptT ($cachedHereBinary (participant, tid, ssh, csh)) . authorizedIfExists $ \(course `E.InnerJoin` submissionGroup `E.InnerJoin` submissionGroupUser) -> do
|
mapExceptT ($cachedHereBinary (participant, tid, ssh, csh)) . authorizedIfExists $ \(course `E.InnerJoin` submissionGroup `E.InnerJoin` submissionGroupUser) -> do
|
||||||
E.on $ submissionGroup E.^. SubmissionGroupId E.==. submissionGroupUser E.^. SubmissionGroupUserSubmissionGroup
|
E.on $ submissionGroup E.^. SubmissionGroupId E.==. submissionGroupUser E.^. SubmissionGroupUserSubmissionGroup
|
||||||
E.on $ course E.^. CourseId E.==. submissionGroup E.^. SubmissionGroupCourse
|
E.on $ course E.^. CourseId E.==. submissionGroup E.^. SubmissionGroupCourse
|
||||||
@ -1274,7 +1260,7 @@ tagAccessPredicate AuthParticipant = APDB $ \mAuthId route _ -> case route of
|
|||||||
E.&&. course E.^. CourseSchool E.==. E.val ssh
|
E.&&. course E.^. CourseSchool E.==. E.val ssh
|
||||||
E.&&. course E.^. CourseShorthand E.==. E.val csh
|
E.&&. course E.^. CourseShorthand E.==. E.val csh
|
||||||
-- participant is a tutorial user
|
-- participant is a tutorial user
|
||||||
when (not onlyActive) $
|
unless onlyActive $
|
||||||
mapExceptT ($cachedHereBinary (participant, tid, ssh, csh)) . authorizedIfExists $ \(course `E.InnerJoin` tutorial `E.InnerJoin` tutorialUser) -> do
|
mapExceptT ($cachedHereBinary (participant, tid, ssh, csh)) . authorizedIfExists $ \(course `E.InnerJoin` tutorial `E.InnerJoin` tutorialUser) -> do
|
||||||
E.on $ tutorial E.^. TutorialId E.==. tutorialUser E.^. TutorialParticipantTutorial
|
E.on $ tutorial E.^. TutorialId E.==. tutorialUser E.^. TutorialParticipantTutorial
|
||||||
E.on $ course E.^. CourseId E.==. tutorial E.^. TutorialCourse
|
E.on $ course E.^. CourseId E.==. tutorial E.^. TutorialCourse
|
||||||
@ -1306,7 +1292,7 @@ tagAccessPredicate AuthParticipant = APDB $ \mAuthId route _ -> case route of
|
|||||||
E.&&. course E.^. CourseSchool E.==. E.val ssh
|
E.&&. course E.^. CourseSchool E.==. E.val ssh
|
||||||
E.&&. course E.^. CourseShorthand E.==. E.val csh
|
E.&&. course E.^. CourseShorthand E.==. E.val csh
|
||||||
-- participant has an exam result for this course
|
-- participant has an exam result for this course
|
||||||
when (not onlyActive) $
|
unless onlyActive $
|
||||||
mapExceptT ($cachedHereBinary (participant, tid, ssh, csh)) . authorizedIfExists $ \(course `E.InnerJoin` exam `E.InnerJoin` examResult) -> do
|
mapExceptT ($cachedHereBinary (participant, tid, ssh, csh)) . authorizedIfExists $ \(course `E.InnerJoin` exam `E.InnerJoin` examResult) -> do
|
||||||
E.on $ examResult E.^. ExamResultExam E.==. exam E.^. ExamId
|
E.on $ examResult E.^. ExamResultExam E.==. exam E.^. ExamId
|
||||||
E.on $ course E.^. CourseId E.==. exam E.^. ExamCourse
|
E.on $ course E.^. CourseId E.==. exam E.^. ExamCourse
|
||||||
@ -1315,7 +1301,7 @@ tagAccessPredicate AuthParticipant = APDB $ \mAuthId route _ -> case route of
|
|||||||
E.&&. course E.^. CourseSchool E.==. E.val ssh
|
E.&&. course E.^. CourseSchool E.==. E.val ssh
|
||||||
E.&&. course E.^. CourseShorthand E.==. E.val csh
|
E.&&. course E.^. CourseShorthand E.==. E.val csh
|
||||||
-- participant is registered for an exam for this course
|
-- participant is registered for an exam for this course
|
||||||
when (not onlyActive) $
|
unless onlyActive $
|
||||||
mapExceptT ($cachedHereBinary (participant, tid, ssh, csh)) . authorizedIfExists $ \(course `E.InnerJoin` exam `E.InnerJoin` examRegistration) -> do
|
mapExceptT ($cachedHereBinary (participant, tid, ssh, csh)) . authorizedIfExists $ \(course `E.InnerJoin` exam `E.InnerJoin` examRegistration) -> do
|
||||||
E.on $ examRegistration E.^. ExamRegistrationExam E.==. exam E.^. ExamId
|
E.on $ examRegistration E.^. ExamRegistrationExam E.==. exam E.^. ExamId
|
||||||
E.on $ course E.^. CourseId E.==. exam E.^. ExamCourse
|
E.on $ course E.^. CourseId E.==. exam E.^. ExamCourse
|
||||||
@ -1323,21 +1309,19 @@ tagAccessPredicate AuthParticipant = APDB $ \mAuthId route _ -> case route of
|
|||||||
E.&&. course E.^. CourseTerm E.==. E.val tid
|
E.&&. course E.^. CourseTerm E.==. E.val tid
|
||||||
E.&&. course E.^. CourseSchool E.==. E.val ssh
|
E.&&. course E.^. CourseSchool E.==. E.val ssh
|
||||||
E.&&. course E.^. CourseShorthand E.==. E.val csh
|
E.&&. course E.^. CourseShorthand E.==. E.val csh
|
||||||
|
|
||||||
return ()
|
|
||||||
tagAccessPredicate AuthApplicant = APDB $ \mAuthId route _ -> case route of
|
tagAccessPredicate AuthApplicant = APDB $ \mAuthId route _ -> case route of
|
||||||
CourseR tid ssh csh (CUserR cID) -> maybeT (unauthorizedI MsgUnauthorizedApplicant) $ do
|
CourseR tid ssh csh (CUserR cID) -> maybeT (unauthorizedI MsgUnauthorizedApplicant) $ do
|
||||||
uid <- catchIfMaybeT (const True :: CryptoIDError -> Bool) $ decrypt cID
|
uid <- catchIfMaybeT (const True :: CryptoIDError -> Bool) $ decrypt cID
|
||||||
isApplicant <- isCourseApplicant tid ssh csh uid
|
isApplicant <- isCourseApplicant tid ssh csh uid
|
||||||
guard isApplicant
|
guard isApplicant
|
||||||
return Authorized
|
return Authorized
|
||||||
|
|
||||||
CourseR tid ssh csh _ -> maybeT (unauthorizedI MsgUnauthorizedApplicantSelf) $ do
|
CourseR tid ssh csh _ -> maybeT (unauthorizedI MsgUnauthorizedApplicantSelf) $ do
|
||||||
uid <- hoistMaybe mAuthId
|
uid <- hoistMaybe mAuthId
|
||||||
isApplicant <- isCourseApplicant tid ssh csh uid
|
isApplicant <- isCourseApplicant tid ssh csh uid
|
||||||
guard isApplicant
|
guard isApplicant
|
||||||
return Authorized
|
return Authorized
|
||||||
|
|
||||||
r -> $unsupportedAuthPredicate AuthApplicant r
|
r -> $unsupportedAuthPredicate AuthApplicant r
|
||||||
where
|
where
|
||||||
isCourseApplicant tid ssh csh uid = lift . $cachedHereBinary (uid, tid, ssh, csh) . E.selectExists . E.from $ \(course `E.InnerJoin` courseApplication) -> do
|
isCourseApplicant tid ssh csh uid = lift . $cachedHereBinary (uid, tid, ssh, csh) . E.selectExists . E.from $ \(course `E.InnerJoin` courseApplication) -> do
|
||||||
@ -1666,8 +1650,8 @@ wouldHaveReadAccessToIff, wouldHaveWriteAccessToIff
|
|||||||
=> [(AuthTag, Bool)] -- ^ Assumptions
|
=> [(AuthTag, Bool)] -- ^ Assumptions
|
||||||
-> Route UniWorX
|
-> Route UniWorX
|
||||||
-> m Bool
|
-> m Bool
|
||||||
wouldHaveReadAccessToIff assumptions route = and2M (fmap not $ hasReadAccessTo route) $ wouldHaveReadAccessTo assumptions route
|
wouldHaveReadAccessToIff assumptions route = and2M (not <$> hasReadAccessTo route) $ wouldHaveReadAccessTo assumptions route
|
||||||
wouldHaveWriteAccessToIff assumptions route = and2M (fmap not $ hasWriteAccessTo route) $ wouldHaveWriteAccessTo assumptions route
|
wouldHaveWriteAccessToIff assumptions route = and2M (not <$> hasWriteAccessTo route) $ wouldHaveWriteAccessTo assumptions route
|
||||||
|
|
||||||
-- | Conditional redirect that hides the URL if the user is not authorized for the route
|
-- | Conditional redirect that hides the URL if the user is not authorized for the route
|
||||||
redirectAccess :: (MonadThrow m, MonadHandler m, HandlerSite m ~ UniWorX) => Route UniWorX -> m a
|
redirectAccess :: (MonadThrow m, MonadHandler m, HandlerSite m ~ UniWorX) => Route UniWorX -> m a
|
||||||
@ -1728,10 +1712,10 @@ instance Yesod UniWorX where
|
|||||||
|
|
||||||
makeSessionBackend app@UniWorX{ appSettings' = AppSettings{..}, ..} = notForBearer . sameSite $ case appSessionStore of
|
makeSessionBackend app@UniWorX{ appSettings' = AppSettings{..}, ..} = notForBearer . sameSite $ case appSessionStore of
|
||||||
SessionStorageMemcachedSql sqlStore
|
SessionStorageMemcachedSql sqlStore
|
||||||
-> mkBackend =<< stateSettings <$> ServerSession.createState sqlStore
|
-> mkBackend . stateSettings =<< ServerSession.createState sqlStore
|
||||||
SessionStorageAcid acidStore
|
SessionStorageAcid acidStore
|
||||||
| appServerSessionAcidFallback
|
| appServerSessionAcidFallback
|
||||||
-> mkBackend =<< stateSettings <$> ServerSession.createState acidStore
|
-> mkBackend . stateSettings =<< ServerSession.createState acidStore
|
||||||
_other
|
_other
|
||||||
-> return Nothing
|
-> return Nothing
|
||||||
where
|
where
|
||||||
@ -1764,7 +1748,7 @@ instance Yesod UniWorX where
|
|||||||
notForBearer' (SessionBackend load)
|
notForBearer' (SessionBackend load)
|
||||||
= let load' req
|
= let load' req
|
||||||
| aHdrs <- mapMaybe (\(h, v) -> v <$ guard (h == W.hAuthorization)) $ W.requestHeaders req
|
| aHdrs <- mapMaybe (\(h, v) -> v <$ guard (h == W.hAuthorization)) $ W.requestHeaders req
|
||||||
, any (is _Just) $ map W.extractBearerAuth aHdrs
|
, any (is _Just . W.extractBearerAuth) aHdrs
|
||||||
= return (mempty, const $ return [])
|
= return (mempty, const $ return [])
|
||||||
| otherwise
|
| otherwise
|
||||||
= load req
|
= load req
|
||||||
@ -1786,7 +1770,7 @@ instance Yesod UniWorX where
|
|||||||
dryRun <- isDryRun
|
dryRun <- isDryRun
|
||||||
if | dryRun -> do
|
if | dryRun -> do
|
||||||
hData <- ask
|
hData <- ask
|
||||||
prevState <- readIORef (handlerState hData)
|
prevState <- readIORef (handlerState hData)
|
||||||
let
|
let
|
||||||
restoreSession =
|
restoreSession =
|
||||||
modifyIORef (handlerState hData) $
|
modifyIORef (handlerState hData) $
|
||||||
@ -1798,7 +1782,7 @@ instance Yesod UniWorX where
|
|||||||
handler' = local (\hd -> hd { handlerEnv = (handlerEnv hd) { rheSite = site', rheChild = site' } }) handler
|
handler' = local (\hd -> hd { handlerEnv = (handlerEnv hd) { rheSite = site', rheChild = site' } }) handler
|
||||||
|
|
||||||
addCustomHeader HeaderDryRun ("1" :: Text)
|
addCustomHeader HeaderDryRun ("1" :: Text)
|
||||||
|
|
||||||
handler' `finally` restoreSession
|
handler' `finally` restoreSession
|
||||||
| otherwise -> handler
|
| otherwise -> handler
|
||||||
updateFavouritesMiddleware :: Handler a -> Handler a
|
updateFavouritesMiddleware :: Handler a -> Handler a
|
||||||
@ -1993,7 +1977,7 @@ updateFavourites :: forall m. (MonadHandler m, HandlerSite m ~ UniWorX)
|
|||||||
updateFavourites cData = void . runMaybeT $ do
|
updateFavourites cData = void . runMaybeT $ do
|
||||||
$logDebugS "updateFavourites" "Updating favourites"
|
$logDebugS "updateFavourites" "Updating favourites"
|
||||||
|
|
||||||
now <- liftIO $ getCurrentTime
|
now <- liftIO getCurrentTime
|
||||||
uid <- MaybeT $ liftHandler maybeAuthId
|
uid <- MaybeT $ liftHandler maybeAuthId
|
||||||
mcid <- for cData $ \(tid, ssh, csh) -> MaybeT . getKeyBy $ TermSchoolCourseShort tid ssh csh
|
mcid <- for cData $ \(tid, ssh, csh) -> MaybeT . getKeyBy $ TermSchoolCourseShort tid ssh csh
|
||||||
User{userMaxFavourites} <- MaybeT $ get uid
|
User{userMaxFavourites} <- MaybeT $ get uid
|
||||||
@ -2107,7 +2091,7 @@ siteLayout' headingOverride widget = do
|
|||||||
[ E.when_ isCurrent E.then_ . E.just $ E.val FavouriteCurrent
|
[ E.when_ isCurrent E.then_ . E.just $ E.val FavouriteCurrent
|
||||||
, E.when_ isAssociated E.then_ . E.just $ E.val FavouriteParticipant
|
, E.when_ isAssociated E.then_ . E.just $ E.val FavouriteParticipant
|
||||||
] (E.else_ $ courseFavourite E.?. CourseFavouriteReason)
|
] (E.else_ $ courseFavourite E.?. CourseFavouriteReason)
|
||||||
|
|
||||||
E.where_ $ ((isFavourite E.||. isAssociated) E.&&. notBlacklist) E.||. isCurrent
|
E.where_ $ ((isFavourite E.||. isAssociated) E.&&. notBlacklist) E.||. isCurrent
|
||||||
|
|
||||||
return (course, reason, courseVisible)
|
return (course, reason, courseVisible)
|
||||||
@ -2138,7 +2122,7 @@ siteLayout' headingOverride widget = do
|
|||||||
$logDebugS "FavouriteQuickActions" $ tshow cK <> " Checking..."
|
$logDebugS "FavouriteQuickActions" $ tshow cK <> " Checking..."
|
||||||
items <- memcachedLimitedKeyTimeoutBy
|
items <- memcachedLimitedKeyTimeoutBy
|
||||||
MemcachedLimitKeyFavourites appFavouritesQuickActionsBurstsize appFavouritesQuickActionsAvgInverseRate 1
|
MemcachedLimitKeyFavourites appFavouritesQuickActionsBurstsize appFavouritesQuickActionsAvgInverseRate 1
|
||||||
(Right <$> appFavouritesQuickActionsCacheTTL)
|
(Right <$> appFavouritesQuickActionsCacheTTL)
|
||||||
appFavouritesQuickActionsTimeout
|
appFavouritesQuickActionsTimeout
|
||||||
cK
|
cK
|
||||||
cK
|
cK
|
||||||
@ -2207,7 +2191,7 @@ siteLayout' headingOverride widget = do
|
|||||||
-> let route = navRoute'
|
-> let route = navRoute'
|
||||||
ident = navIdent
|
ident = navIdent
|
||||||
in $(widgetFile "widgets/navbar/item")
|
in $(widgetFile "widgets/navbar/item")
|
||||||
NavPageActionPrimary{ navLink = navLink@NavLink{..}, .. }
|
NavPageActionPrimary{ navLink = navLink@NavLink{..} }
|
||||||
-> let pWidget
|
-> let pWidget
|
||||||
| NavTypeLink{..} <- navType
|
| NavTypeLink{..} <- navType
|
||||||
, navModal
|
, navModal
|
||||||
@ -2226,7 +2210,7 @@ siteLayout' headingOverride widget = do
|
|||||||
sWidgets = navChildren'
|
sWidgets = navChildren'
|
||||||
& map (\(l, i, r) -> navWidget (NavPageActionSecondary l, i, Just r, []))
|
& map (\(l, i, r) -> navWidget (NavPageActionSecondary l, i, Just r, []))
|
||||||
in $(widgetFile "widgets/pageaction/primary-wrapper")
|
in $(widgetFile "widgets/pageaction/primary-wrapper")
|
||||||
NavPageActionSecondary{ navLink = navLink@NavLink{..}, .. }
|
NavPageActionSecondary{ navLink = navLink@NavLink{..} }
|
||||||
| NavTypeLink{..} <- navType
|
| NavTypeLink{..} <- navType
|
||||||
, navModal
|
, navModal
|
||||||
-> customModal Modal
|
-> customModal Modal
|
||||||
@ -2352,7 +2336,7 @@ getSystemMessageState smId = liftHandler $ do
|
|||||||
applySystemMessages :: (MonadHandler m, HandlerSite m ~ UniWorX) => m ()
|
applySystemMessages :: (MonadHandler m, HandlerSite m ~ UniWorX) => m ()
|
||||||
applySystemMessages = liftHandler . maybeT_ . catchMPlus (Proxy @CryptoIDError) $ do
|
applySystemMessages = liftHandler . maybeT_ . catchMPlus (Proxy @CryptoIDError) $ do
|
||||||
lift $ maybeAuthId >>= traverse_ syncSystemMessageHidden
|
lift $ maybeAuthId >>= traverse_ syncSystemMessageHidden
|
||||||
|
|
||||||
cRoute <- lift getCurrentRoute
|
cRoute <- lift getCurrentRoute
|
||||||
guard $ cRoute /= Just NewsR
|
guard $ cRoute /= Just NewsR
|
||||||
|
|
||||||
@ -2369,14 +2353,14 @@ applySystemMessages = liftHandler . maybeT_ . catchMPlus (Proxy @CryptoIDError)
|
|||||||
, systemMessageHiddenTime
|
, systemMessageHiddenTime
|
||||||
}
|
}
|
||||||
[ SystemMessageHiddenTime =. systemMessageHiddenTime ]
|
[ SystemMessageHiddenTime =. systemMessageHiddenTime ]
|
||||||
|
|
||||||
when (maybe False (maybe (const True) (<=) userSystemMessageHidden) userSystemMessageUnhidden) $ do
|
when (maybe False (maybe (const True) (<=) userSystemMessageHidden) userSystemMessageUnhidden) $ do
|
||||||
deleteBy $ UniqueSystemMessageHidden uid smId
|
deleteBy $ UniqueSystemMessageHidden uid smId
|
||||||
|
|
||||||
modifyRegisteredCookieJson CookieSystemMessageState $ \(fold -> MergeHashMap hm)
|
modifyRegisteredCookieJson CookieSystemMessageState $ \(fold -> MergeHashMap hm)
|
||||||
-> fmap MergeHashMap . assertM' (/= mempty) $
|
-> fmap MergeHashMap . assertM' (/= mempty) $
|
||||||
HashMap.update (\smSt' -> assertM' (/= mempty) $ smSt' { userSystemMessageHidden = Nothing, userSystemMessageUnhidden = Nothing }) cID hm
|
HashMap.update (\smSt' -> assertM' (/= mempty) $ smSt' { userSystemMessageHidden = Nothing, userSystemMessageUnhidden = Nothing }) cID hm
|
||||||
|
|
||||||
applyMessage (Entity smId SystemMessage{..}) = maybeT_ $ do
|
applyMessage (Entity smId SystemMessage{..}) = maybeT_ $ do
|
||||||
guard $ not systemMessageNewsOnly
|
guard $ not systemMessageNewsOnly
|
||||||
|
|
||||||
@ -2436,7 +2420,7 @@ instance YesodBreadcrumbs UniWorX where
|
|||||||
User{..} <- MaybeT . runDB $ get uid
|
User{..} <- MaybeT . runDB $ get uid
|
||||||
return (userDisplayName, Just UsersR)
|
return (userDisplayName, Just UsersR)
|
||||||
breadcrumb (AdminUserDeleteR cID) = i18nCrumb MsgBreadcrumbUserDelete . Just $ AdminUserR cID
|
breadcrumb (AdminUserDeleteR cID) = i18nCrumb MsgBreadcrumbUserDelete . Just $ AdminUserR cID
|
||||||
breadcrumb (AdminHijackUserR cID) = i18nCrumb MsgBreadcrumbUserHijack . Just $ AdminUserR cID
|
breadcrumb (AdminHijackUserR cID) = i18nCrumb MsgBreadcrumbUserHijack . Just $ AdminUserR cID
|
||||||
breadcrumb (UserNotificationR cID) = do
|
breadcrumb (UserNotificationR cID) = do
|
||||||
mayList <- hasReadAccessTo UsersR
|
mayList <- hasReadAccessTo UsersR
|
||||||
if
|
if
|
||||||
@ -2455,12 +2439,12 @@ instance YesodBreadcrumbs UniWorX where
|
|||||||
breadcrumb AdminFunctionaryInviteR = i18nCrumb MsgBreadcrumbFunctionaryInvite Nothing
|
breadcrumb AdminFunctionaryInviteR = i18nCrumb MsgBreadcrumbFunctionaryInvite Nothing
|
||||||
|
|
||||||
breadcrumb AdminR = i18nCrumb MsgAdminHeading Nothing
|
breadcrumb AdminR = i18nCrumb MsgAdminHeading Nothing
|
||||||
breadcrumb AdminFeaturesR = i18nCrumb MsgAdminFeaturesHeading $ Just AdminR
|
breadcrumb AdminFeaturesR = i18nCrumb MsgAdminFeaturesHeading $ Just AdminR
|
||||||
breadcrumb AdminTestR = i18nCrumb MsgMenuAdminTest $ Just AdminR
|
breadcrumb AdminTestR = i18nCrumb MsgMenuAdminTest $ Just AdminR
|
||||||
breadcrumb AdminErrMsgR = i18nCrumb MsgMenuAdminErrMsg $ Just AdminR
|
breadcrumb AdminErrMsgR = i18nCrumb MsgMenuAdminErrMsg $ Just AdminR
|
||||||
breadcrumb AdminTokensR = i18nCrumb MsgMenuAdminTokens $ Just AdminR
|
breadcrumb AdminTokensR = i18nCrumb MsgMenuAdminTokens $ Just AdminR
|
||||||
breadcrumb AdminCrontabR = i18nCrumb MsgBreadcrumbAdminCrontab $ Just AdminR
|
breadcrumb AdminCrontabR = i18nCrumb MsgBreadcrumbAdminCrontab $ Just AdminR
|
||||||
|
|
||||||
breadcrumb SchoolListR = i18nCrumb MsgMenuSchoolList $ Just AdminR
|
breadcrumb SchoolListR = i18nCrumb MsgMenuSchoolList $ Just AdminR
|
||||||
breadcrumb (SchoolR ssh SchoolEditR) = maybeT (i18nCrumb MsgBreadcrumbSchool $ Just SchoolListR) $ do
|
breadcrumb (SchoolR ssh SchoolEditR) = maybeT (i18nCrumb MsgBreadcrumbSchool $ Just SchoolListR) $ do
|
||||||
School{..} <- MaybeT . runDB $ get ssh
|
School{..} <- MaybeT . runDB $ get ssh
|
||||||
@ -2514,12 +2498,12 @@ instance YesodBreadcrumbs UniWorX where
|
|||||||
AShowR -> maybeT (i18nCrumb MsgBreadcrumbAllocation $ Just AllocationListR) $ do
|
AShowR -> maybeT (i18nCrumb MsgBreadcrumbAllocation $ Just AllocationListR) $ do
|
||||||
mr <- getMessageRender
|
mr <- getMessageRender
|
||||||
Entity _ Allocation{allocationName} <- MaybeT . runDB . getBy $ TermSchoolAllocationShort tid ssh ash
|
Entity _ Allocation{allocationName} <- MaybeT . runDB . getBy $ TermSchoolAllocationShort tid ssh ash
|
||||||
return ([st|#{allocationName} (#{mr (ShortTermIdentifier (unTermKey tid))}, #{CI.original (unSchoolKey ssh)})|], Just $ AllocationListR)
|
return ([st|#{allocationName} (#{mr (ShortTermIdentifier (unTermKey tid))}, #{CI.original (unSchoolKey ssh)})|], Just AllocationListR)
|
||||||
ARegisterR -> i18nCrumb MsgBreadcrumbAllocationRegister . Just $ AllocationR tid ssh ash AShowR
|
ARegisterR -> i18nCrumb MsgBreadcrumbAllocationRegister . Just $ AllocationR tid ssh ash AShowR
|
||||||
AApplyR cID -> maybeT (i18nCrumb MsgBreadcrumbCourse . Just $ AllocationR tid ssh ash AShowR) $ do
|
AApplyR cID -> maybeT (i18nCrumb MsgBreadcrumbCourse . Just $ AllocationR tid ssh ash AShowR) $ do
|
||||||
cid <- decrypt cID
|
cid <- decrypt cID
|
||||||
Course{..} <- hoist runDB $ do
|
Course{..} <- hoist runDB $ do
|
||||||
aid <- MaybeT . getKeyBy $ TermSchoolAllocationShort tid ssh ash
|
aid <- MaybeT . getKeyBy $ TermSchoolAllocationShort tid ssh ash
|
||||||
guardM . lift $ exists [ AllocationCourseAllocation ==. aid, AllocationCourseCourse ==. cid ]
|
guardM . lift $ exists [ AllocationCourseAllocation ==. aid, AllocationCourseCourse ==. cid ]
|
||||||
MaybeT $ get cid
|
MaybeT $ get cid
|
||||||
return (CI.original courseName, Just $ AllocationR tid ssh ash AShowR)
|
return (CI.original courseName, Just $ AllocationR tid ssh ash AShowR)
|
||||||
@ -2571,7 +2555,7 @@ instance YesodBreadcrumbs UniWorX where
|
|||||||
CNDeleteR -> i18nCrumb MsgBreadcrumbCourseNewsDelete . Just $ CNewsR tid ssh csh cID CNShowR
|
CNDeleteR -> i18nCrumb MsgBreadcrumbCourseNewsDelete . Just $ CNewsR tid ssh csh cID CNShowR
|
||||||
CNArchiveR -> i18nCrumb MsgBreadcrumbCourseNewsArchive . Just $ CNewsR tid ssh csh cID CNShowR
|
CNArchiveR -> i18nCrumb MsgBreadcrumbCourseNewsArchive . Just $ CNewsR tid ssh csh cID CNShowR
|
||||||
CNFileR _ -> i18nCrumb MsgBreadcrumbCourseNewsFile . Just $ CNewsR tid ssh csh cID CNShowR
|
CNFileR _ -> i18nCrumb MsgBreadcrumbCourseNewsFile . Just $ CNewsR tid ssh csh cID CNShowR
|
||||||
|
|
||||||
breadcrumb (CourseR tid ssh csh CEventsNewR) = i18nCrumb MsgMenuCourseEventNew . Just $ CourseR tid ssh csh CShowR
|
breadcrumb (CourseR tid ssh csh CEventsNewR) = i18nCrumb MsgMenuCourseEventNew . Just $ CourseR tid ssh csh CShowR
|
||||||
breadcrumb (CourseR tid ssh csh (CourseEventR _cID sRoute)) = case sRoute of
|
breadcrumb (CourseR tid ssh csh (CourseEventR _cID sRoute)) = case sRoute of
|
||||||
CEvEditR -> i18nCrumb MsgMenuCourseEventEdit . Just $ CourseR tid ssh csh CShowR
|
CEvEditR -> i18nCrumb MsgMenuCourseEventEdit . Just $ CourseR tid ssh csh CShowR
|
||||||
@ -2668,7 +2652,7 @@ instance YesodBreadcrumbs UniWorX where
|
|||||||
breadcrumb CorrectionsDownloadR = i18nCrumb MsgMenuCorrectionsDownload $ Just CorrectionsR
|
breadcrumb CorrectionsDownloadR = i18nCrumb MsgMenuCorrectionsDownload $ Just CorrectionsR
|
||||||
|
|
||||||
breadcrumb (CryptoUUIDDispatchR _) = i18nCrumb MsgBreadcrumbCryptoIDDispatch Nothing
|
breadcrumb (CryptoUUIDDispatchR _) = i18nCrumb MsgBreadcrumbCryptoIDDispatch Nothing
|
||||||
|
|
||||||
breadcrumb (MessageR _) = do
|
breadcrumb (MessageR _) = do
|
||||||
mayList <- (== Authorized) <$> evalAccess MessageListR False
|
mayList <- (== Authorized) <$> evalAccess MessageListR False
|
||||||
if
|
if
|
||||||
@ -2695,9 +2679,9 @@ instance YesodBreadcrumbs UniWorX where
|
|||||||
| otherwise -> EExamListR
|
| otherwise -> EExamListR
|
||||||
EEEditR -> i18nCrumb MsgBreadcrumbExternalExamEdit . Just $ EExamR tid ssh coursen examn EEShowR
|
EEEditR -> i18nCrumb MsgBreadcrumbExternalExamEdit . Just $ EExamR tid ssh coursen examn EEShowR
|
||||||
EEUsersR -> i18nCrumb MsgBreadcrumbExternalExamUsers . Just $ EExamR tid ssh coursen examn EEShowR
|
EEUsersR -> i18nCrumb MsgBreadcrumbExternalExamUsers . Just $ EExamR tid ssh coursen examn EEShowR
|
||||||
EEGradesR -> i18nCrumb MsgBreadcrumbExternalExamGrades . Just $ EExamR tid ssh coursen examn EEShowR
|
EEGradesR -> i18nCrumb MsgBreadcrumbExternalExamGrades . Just $ EExamR tid ssh coursen examn EEShowR
|
||||||
EEStaffInviteR -> i18nCrumb MsgBreadcrumbExternalExamStaffInvite . Just $ EExamR tid ssh coursen examn EEShowR
|
EEStaffInviteR -> i18nCrumb MsgBreadcrumbExternalExamStaffInvite . Just $ EExamR tid ssh coursen examn EEShowR
|
||||||
|
|
||||||
-- breadcrumb _ = return ("Uni2work", Nothing) -- Default is no breadcrumb at all
|
-- breadcrumb _ = return ("Uni2work", Nothing) -- Default is no breadcrumb at all
|
||||||
|
|
||||||
submissionList :: TermId -> CourseShorthand -> SheetName -> UserId -> DB [E.Value SubmissionId]
|
submissionList :: TermId -> CourseShorthand -> SheetName -> UserId -> DB [E.Value SubmissionId]
|
||||||
@ -2780,7 +2764,7 @@ defaultLinks = fmap catMaybes . mapM runMaybeT $ -- Define the menu items of the
|
|||||||
}
|
}
|
||||||
, do
|
, do
|
||||||
mCurrentRoute <- getCurrentRoute
|
mCurrentRoute <- getCurrentRoute
|
||||||
|
|
||||||
return NavHeader
|
return NavHeader
|
||||||
{ navHeaderRole = NavHeaderSecondary
|
{ navHeaderRole = NavHeaderSecondary
|
||||||
, navIcon = IconMenuHelp
|
, navIcon = IconMenuHelp
|
||||||
@ -2792,7 +2776,7 @@ defaultLinks = fmap catMaybes . mapM runMaybeT $ -- Define the menu items of the
|
|||||||
, navQuick' = mempty
|
, navQuick' = mempty
|
||||||
, navForceActive = False
|
, navForceActive = False
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
, return $ NavFooter NavLink
|
, return $ NavFooter NavLink
|
||||||
{ navLabel = MsgMenuDataProt
|
{ navLabel = MsgMenuDataProt
|
||||||
, navRoute = LegalR :#: ("data-protection" :: Text)
|
, navRoute = LegalR :#: ("data-protection" :: Text)
|
||||||
@ -2901,7 +2885,7 @@ defaultLinks = fmap catMaybes . mapM runMaybeT $ -- Define the menu items of the
|
|||||||
{ navHeaderRole = NavHeaderPrimary
|
{ navHeaderRole = NavHeaderPrimary
|
||||||
, navLabel = SomeMessage MsgAdminHeading
|
, navLabel = SomeMessage MsgAdminHeading
|
||||||
, navIcon = IconMenuAdmin
|
, navIcon = IconMenuAdmin
|
||||||
, navChildren =
|
, navChildren =
|
||||||
[ NavLink
|
[ NavLink
|
||||||
{ navLabel = MsgMenuUsers
|
{ navLabel = MsgMenuUsers
|
||||||
, navRoute = UsersR
|
, navRoute = UsersR
|
||||||
@ -2972,7 +2956,7 @@ defaultLinks = fmap catMaybes . mapM runMaybeT $ -- Define the menu items of the
|
|||||||
{ navHeaderRole = NavHeaderPrimary
|
{ navHeaderRole = NavHeaderPrimary
|
||||||
, navLabel = SomeMessage (mempty :: Text)
|
, navLabel = SomeMessage (mempty :: Text)
|
||||||
, navIcon = IconMenuExtra
|
, navIcon = IconMenuExtra
|
||||||
, navChildren =
|
, navChildren =
|
||||||
[ NavLink
|
[ NavLink
|
||||||
{ navLabel = MsgMenuCourseNew
|
{ navLabel = MsgMenuCourseNew
|
||||||
, navRoute = CourseNewR
|
, navRoute = CourseNewR
|
||||||
@ -3198,7 +3182,7 @@ pageActions (CourseR tid ssh csh CShowR) = do
|
|||||||
, navAccess' = do
|
, navAccess' = do
|
||||||
uid <- requireAuthId
|
uid <- requireAuthId
|
||||||
runDB $ do
|
runDB $ do
|
||||||
cid <- getKeyBy404 $ TermSchoolCourseShort tid ssh csh
|
cid <- getKeyBy404 $ TermSchoolCourseShort tid ssh csh
|
||||||
E.selectExists $ do
|
E.selectExists $ do
|
||||||
(_school, isForced) <- courseExamOfficeSchools (E.val uid) (E.val cid)
|
(_school, isForced) <- courseExamOfficeSchools (E.val uid) (E.val cid)
|
||||||
E.where_ $ E.not_ isForced
|
E.where_ $ E.not_ isForced
|
||||||
@ -3476,7 +3460,7 @@ pageActions HelpR = return
|
|||||||
, ("allocations", MsgInfoLecturerAllocations)
|
, ("allocations", MsgInfoLecturerAllocations)
|
||||||
] :: [(Text, UniWorXMessage)]
|
] :: [(Text, UniWorXMessage)]
|
||||||
return NavLink
|
return NavLink
|
||||||
{ navLabel
|
{ navLabel
|
||||||
, navRoute = InfoLecturerR :#: section
|
, navRoute = InfoLecturerR :#: section
|
||||||
, navAccess' = return True
|
, navAccess' = return True
|
||||||
, navType = NavTypeLink { navModal = False }
|
, navType = NavTypeLink { navModal = False }
|
||||||
@ -3591,7 +3575,7 @@ pageActions (AllocationR tid ssh ash AShowR) = return
|
|||||||
}
|
}
|
||||||
, navChildren = []
|
, navChildren = []
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
pageActions (AllocationR tid ssh ash AUsersR) = return
|
pageActions (AllocationR tid ssh ash AUsersR) = return
|
||||||
[ NavPageActionPrimary
|
[ NavPageActionPrimary
|
||||||
{ navLink = NavLink
|
{ navLink = NavLink
|
||||||
@ -3615,7 +3599,7 @@ pageActions (AllocationR tid ssh ash AUsersR) = return
|
|||||||
}
|
}
|
||||||
, navChildren = []
|
, navChildren = []
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
pageActions CourseListR = do
|
pageActions CourseListR = do
|
||||||
participantsSecondary <- pageQuickActions NavQuickViewPageActionSecondary ParticipantsListR
|
participantsSecondary <- pageQuickActions NavQuickViewPageActionSecondary ParticipantsListR
|
||||||
return
|
return
|
||||||
@ -3652,7 +3636,7 @@ pageActions CourseListR = do
|
|||||||
}
|
}
|
||||||
, navChildren = participantsSecondary
|
, navChildren = participantsSecondary
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
pageActions CourseNewR = return
|
pageActions CourseNewR = return
|
||||||
[ NavPageActionPrimary
|
[ NavPageActionPrimary
|
||||||
{ navLink = NavLink
|
{ navLink = NavLink
|
||||||
@ -3692,14 +3676,13 @@ pageActions (CourseR tid ssh csh CCorrectionsR) = return
|
|||||||
case muid of
|
case muid of
|
||||||
Nothing -> return False
|
Nothing -> return False
|
||||||
(Just uid) -> do
|
(Just uid) -> do
|
||||||
ok <- runDB . E.selectExists . E.from $ \(course `E.InnerJoin` sheet `E.InnerJoin` submission) -> do
|
runDB . E.selectExists . E.from $ \(course `E.InnerJoin` sheet `E.InnerJoin` submission) -> do
|
||||||
E.on $ submission E.^. SubmissionSheet E.==. sheet E.^. SheetId
|
E.on $ submission E.^. SubmissionSheet E.==. sheet E.^. SheetId
|
||||||
E.on $ sheet E.^. SheetCourse E.==. course E.^. CourseId
|
E.on $ sheet E.^. SheetCourse E.==. course E.^. CourseId
|
||||||
E.where_ $ submission E.^. SubmissionRatingBy E.==. E.just (E.val uid)
|
E.where_ $ submission E.^. SubmissionRatingBy E.==. E.just (E.val uid)
|
||||||
E.&&. course E.^. CourseTerm E.==. E.val tid
|
E.&&. course E.^. CourseTerm E.==. E.val tid
|
||||||
E.&&. course E.^. CourseSchool E.==. E.val ssh
|
E.&&. course E.^. CourseSchool E.==. E.val ssh
|
||||||
E.&&. course E.^. CourseShorthand E.==. E.val csh
|
E.&&. course E.^. CourseShorthand E.==. E.val csh
|
||||||
return ok
|
|
||||||
, navType = NavTypeLink { navModal = False }
|
, navType = NavTypeLink { navModal = False }
|
||||||
, navQuick' = navQuick NavQuickViewPageActionSecondary
|
, navQuick' = navQuick NavQuickViewPageActionSecondary
|
||||||
, navForceActive = False
|
, navForceActive = False
|
||||||
@ -3723,7 +3706,7 @@ pageActions (CourseR tid ssh csh SheetListR) = do
|
|||||||
, navChildren = correctionsSecondary
|
, navChildren = correctionsSecondary
|
||||||
}
|
}
|
||||||
showCorrections <- maybeT (return False) $ True <$ navAccess navCorrections
|
showCorrections <- maybeT (return False) $ True <$ navAccess navCorrections
|
||||||
|
|
||||||
return $
|
return $
|
||||||
[ NavPageActionPrimary
|
[ NavPageActionPrimary
|
||||||
{ navLink = NavLink
|
{ navLink = NavLink
|
||||||
@ -4070,7 +4053,7 @@ pageActions (CSheetR tid ssh csh shn SShowR) = do
|
|||||||
, navChildren = subsSecondary
|
, navChildren = subsSecondary
|
||||||
}
|
}
|
||||||
showSubmissions <- maybeT (return False) $ True <$ navAccess navSubmissions
|
showSubmissions <- maybeT (return False) $ True <$ navAccess navSubmissions
|
||||||
|
|
||||||
return $
|
return $
|
||||||
[ NavPageActionPrimary
|
[ NavPageActionPrimary
|
||||||
{ navLink = NavLink
|
{ navLink = NavLink
|
||||||
@ -4513,19 +4496,19 @@ pageHeading UsersR
|
|||||||
= Just $ i18nHeading MsgUsers
|
= Just $ i18nHeading MsgUsers
|
||||||
pageHeading (AdminUserR _)
|
pageHeading (AdminUserR _)
|
||||||
= Just $ i18nHeading MsgAdminUserHeading
|
= Just $ i18nHeading MsgAdminUserHeading
|
||||||
pageHeading (AdminTestR)
|
pageHeading AdminTestR
|
||||||
= Just $ [whamlet|Internal Code Demonstration Page|]
|
= Just [whamlet|Internal Code Demonstration Page|]
|
||||||
pageHeading (AdminErrMsgR)
|
pageHeading AdminErrMsgR
|
||||||
= Just $ i18nHeading MsgErrMsgHeading
|
= Just $ i18nHeading MsgErrMsgHeading
|
||||||
|
|
||||||
pageHeading (InfoR)
|
pageHeading InfoR
|
||||||
= Just $ i18nHeading MsgInfoHeading
|
= Just $ i18nHeading MsgInfoHeading
|
||||||
pageHeading (LegalR)
|
pageHeading LegalR
|
||||||
= Just $ i18nHeading MsgLegalHeading
|
= Just $ i18nHeading MsgLegalHeading
|
||||||
pageHeading (VersionR)
|
pageHeading VersionR
|
||||||
= Just $ i18nHeading MsgVersionHeading
|
= Just $ i18nHeading MsgVersionHeading
|
||||||
|
|
||||||
pageHeading (HelpR)
|
pageHeading HelpR
|
||||||
= Just $ i18nHeading MsgHelpRequest
|
= Just $ i18nHeading MsgHelpRequest
|
||||||
|
|
||||||
pageHeading ProfileR
|
pageHeading ProfileR
|
||||||
@ -4548,8 +4531,8 @@ pageHeading (TermSchoolCourseListR tid ssh)
|
|||||||
School{schoolName=school} <- handlerToWidget $ runDB $ get404 ssh
|
School{schoolName=school} <- handlerToWidget $ runDB $ get404 ssh
|
||||||
i18nHeading $ MsgTermSchoolCourseListHeading tid school
|
i18nHeading $ MsgTermSchoolCourseListHeading tid school
|
||||||
|
|
||||||
pageHeading (CourseListR)
|
pageHeading CourseListR
|
||||||
= Just $ i18nHeading $ MsgCourseListTitle
|
= Just $ i18nHeading MsgCourseListTitle
|
||||||
pageHeading CourseNewR
|
pageHeading CourseNewR
|
||||||
= Just $ i18nHeading MsgCourseNewHeading
|
= Just $ i18nHeading MsgCourseNewHeading
|
||||||
pageHeading (CourseR tid ssh csh CShowR)
|
pageHeading (CourseR tid ssh csh CShowR)
|
||||||
@ -4661,25 +4644,25 @@ routeNormalizers =
|
|||||||
return $ route & typesUsing @RouteChildren @CourseShorthand . filtered (== csh) .~ courseShorthand
|
return $ route & typesUsing @RouteChildren @CourseShorthand . filtered (== csh) .~ courseShorthand
|
||||||
ncSheet = maybeOrig $ \route -> do
|
ncSheet = maybeOrig $ \route -> do
|
||||||
CSheetR tid ssh csh shn _ <- return route
|
CSheetR tid ssh csh shn _ <- return route
|
||||||
Entity cid Course{..} <- MaybeT . $cachedHereBinary (tid, ssh, csh) . lift . getBy $ TermSchoolCourseShort tid ssh csh
|
cid <- MaybeT . $cachedHereBinary (tid, ssh, csh) . lift . getKeyBy $ TermSchoolCourseShort tid ssh csh
|
||||||
Entity _ Sheet{..} <- MaybeT . $cachedHereBinary (cid, shn) . lift . getBy $ CourseSheet cid shn
|
Entity _ Sheet{..} <- MaybeT . $cachedHereBinary (cid, shn) . lift . getBy $ CourseSheet cid shn
|
||||||
caseChanged shn sheetName
|
caseChanged shn sheetName
|
||||||
return $ route & typesUsing @RouteChildren @SheetName . filtered (== shn) .~ sheetName
|
return $ route & typesUsing @RouteChildren @SheetName . filtered (== shn) .~ sheetName
|
||||||
ncMaterial = maybeOrig $ \route -> do
|
ncMaterial = maybeOrig $ \route -> do
|
||||||
CMaterialR tid ssh csh mnm _ <- return route
|
CMaterialR tid ssh csh mnm _ <- return route
|
||||||
Entity cid Course{..} <- MaybeT . $cachedHereBinary (tid, ssh, csh) . lift . getBy $ TermSchoolCourseShort tid ssh csh
|
cid <- MaybeT . $cachedHereBinary (tid, ssh, csh) . lift . getKeyBy $ TermSchoolCourseShort tid ssh csh
|
||||||
Entity _ Material{..} <- MaybeT . $cachedHereBinary (cid, mnm) . lift . getBy $ UniqueMaterial cid mnm
|
Entity _ Material{..} <- MaybeT . $cachedHereBinary (cid, mnm) . lift . getBy $ UniqueMaterial cid mnm
|
||||||
caseChanged mnm materialName
|
caseChanged mnm materialName
|
||||||
return $ route & typesUsing @RouteChildren @MaterialName . filtered (== mnm) .~ materialName
|
return $ route & typesUsing @RouteChildren @MaterialName . filtered (== mnm) .~ materialName
|
||||||
ncTutorial = maybeOrig $ \route -> do
|
ncTutorial = maybeOrig $ \route -> do
|
||||||
CTutorialR tid ssh csh tutn _ <- return route
|
CTutorialR tid ssh csh tutn _ <- return route
|
||||||
Entity cid Course{..} <- MaybeT . $cachedHereBinary (tid, ssh, csh) . lift . getBy $ TermSchoolCourseShort tid ssh csh
|
cid <- MaybeT . $cachedHereBinary (tid, ssh, csh) . lift . getKeyBy $ TermSchoolCourseShort tid ssh csh
|
||||||
Entity _ Tutorial{..} <- MaybeT . $cachedHereBinary (cid, tutn) . lift . getBy $ UniqueTutorial cid tutn
|
Entity _ Tutorial{..} <- MaybeT . $cachedHereBinary (cid, tutn) . lift . getBy $ UniqueTutorial cid tutn
|
||||||
caseChanged tutn tutorialName
|
caseChanged tutn tutorialName
|
||||||
return $ route & typesUsing @RouteChildren @TutorialName . filtered (== tutn) .~ tutorialName
|
return $ route & typesUsing @RouteChildren @TutorialName . filtered (== tutn) .~ tutorialName
|
||||||
ncExam = maybeOrig $ \route -> do
|
ncExam = maybeOrig $ \route -> do
|
||||||
CExamR tid ssh csh examn _ <- return route
|
CExamR tid ssh csh examn _ <- return route
|
||||||
Entity cid Course{..} <- MaybeT . $cachedHereBinary (tid, ssh, csh) . lift . getBy $ TermSchoolCourseShort tid ssh csh
|
cid <- MaybeT . $cachedHereBinary (tid, ssh, csh) . lift . getKeyBy $ TermSchoolCourseShort tid ssh csh
|
||||||
Entity _ Exam{..} <- MaybeT . $cachedHereBinary (cid, examn) . lift . getBy $ UniqueExam cid examn
|
Entity _ Exam{..} <- MaybeT . $cachedHereBinary (cid, examn) . lift . getBy $ UniqueExam cid examn
|
||||||
caseChanged examn examName
|
caseChanged examn examName
|
||||||
return $ route & typesUsing @RouteChildren @ExamName . filtered (== examn) .~ examName
|
return $ route & typesUsing @RouteChildren @ExamName . filtered (== examn) .~ examName
|
||||||
@ -4725,7 +4708,7 @@ runSqlPoolRetry :: forall m a backend.
|
|||||||
=> ReaderT backend m a
|
=> ReaderT backend m a
|
||||||
-> Pool backend
|
-> Pool backend
|
||||||
-> m a
|
-> m a
|
||||||
runSqlPoolRetry action pool = do
|
runSqlPoolRetry action pool = do
|
||||||
let policy = Retry.fullJitterBackoff 1e3 & Retry.limitRetriesByCumulativeDelay 10e6
|
let policy = Retry.fullJitterBackoff 1e3 & Retry.limitRetriesByCumulativeDelay 10e6
|
||||||
handlers = Retry.skipAsyncExceptions `snoc` Retry.logRetries suggestRetry logRetry
|
handlers = Retry.skipAsyncExceptions `snoc` Retry.logRetries suggestRetry logRetry
|
||||||
where suggestRetry :: IOException -> m Bool
|
where suggestRetry :: IOException -> m Bool
|
||||||
@ -4748,7 +4731,7 @@ runSqlPoolRetry action pool = do
|
|||||||
runDBRead :: ReaderT SqlReadBackend Handler a -> Handler a
|
runDBRead :: ReaderT SqlReadBackend Handler a -> Handler a
|
||||||
runDBRead action = do
|
runDBRead action = do
|
||||||
$logDebugS "YesodPersist" "runDBRead"
|
$logDebugS "YesodPersist" "runDBRead"
|
||||||
runSqlPoolRetry (withReaderT SqlReadBackend action) =<< appConnPool <$> getYesod
|
runSqlPoolRetry (withReaderT SqlReadBackend action) . appConnPool =<< getYesod
|
||||||
|
|
||||||
-- How to run database actions.
|
-- How to run database actions.
|
||||||
instance YesodPersist UniWorX where
|
instance YesodPersist UniWorX where
|
||||||
@ -4762,7 +4745,7 @@ instance YesodPersist UniWorX where
|
|||||||
| dryRun = action <* transactionUndo
|
| dryRun = action <* transactionUndo
|
||||||
| otherwise = action
|
| otherwise = action
|
||||||
|
|
||||||
runSqlPoolRetry action' =<< appConnPool <$> getYesod
|
runSqlPoolRetry action' . appConnPool =<< getYesod
|
||||||
|
|
||||||
instance YesodPersistRunner UniWorX where
|
instance YesodPersistRunner UniWorX where
|
||||||
getDBRunner = do
|
getDBRunner = do
|
||||||
@ -4914,7 +4897,7 @@ upsertCampusUser plugin ldapData = do
|
|||||||
-- , UserDisplayName =. userDisplayName
|
-- , UserDisplayName =. userDisplayName
|
||||||
, UserFirstName =. userFirstName
|
, UserFirstName =. userFirstName
|
||||||
, UserSurname =. userSurname
|
, UserSurname =. userSurname
|
||||||
, UserTitle =. userTitle
|
, UserTitle =. userTitle
|
||||||
, UserEmail =. userEmail
|
, UserEmail =. userEmail
|
||||||
, UserSex =. userSex
|
, UserSex =. userSex
|
||||||
, UserLastLdapSynchronisation =. Just now
|
, UserLastLdapSynchronisation =. Just now
|
||||||
@ -4992,7 +4975,7 @@ upsertCampusUser plugin ldapData = do
|
|||||||
knownParents <- lift $ map (studySubTermsParent . entityVal) <$> selectList [ StudySubTermsChild ==. subterm ] []
|
knownParents <- lift $ map (studySubTermsParent . entityVal) <$> selectList [ StudySubTermsChild ==. subterm ] []
|
||||||
let matchingFeatures = case knownParents of
|
let matchingFeatures = case knownParents of
|
||||||
[] -> filter ((== subSemester) . studyFeaturesSemester) unusedFeats
|
[] -> filter ((== subSemester) . studyFeaturesSemester) unusedFeats
|
||||||
ps -> filter (\StudyFeatures{studyFeaturesField, studyFeaturesSemester} -> any (== studyFeaturesField) ps && studyFeaturesSemester == subSemester) unusedFeats
|
ps -> filter (\StudyFeatures{studyFeaturesField, studyFeaturesSemester} -> elem studyFeaturesField ps && studyFeaturesSemester == subSemester) unusedFeats
|
||||||
when (null knownParents) . forM_ matchingFeatures $ \StudyFeatures{..} ->
|
when (null knownParents) . forM_ matchingFeatures $ \StudyFeatures{..} ->
|
||||||
tell $ Set.singleton (subterm, Just studyFeaturesField)
|
tell $ Set.singleton (subterm, Just studyFeaturesField)
|
||||||
if
|
if
|
||||||
@ -5051,12 +5034,12 @@ upsertCampusUser plugin ldapData = do
|
|||||||
insertMaybe studyFeaturesDegree $ StudyDegree (unStudyDegreeKey studyFeaturesDegree) Nothing Nothing
|
insertMaybe studyFeaturesDegree $ StudyDegree (unStudyDegreeKey studyFeaturesDegree) Nothing Nothing
|
||||||
insertMaybe studyFeaturesField $ StudyTerms (unStudyTermsKey studyFeaturesField) Nothing Nothing Nothing Nothing
|
insertMaybe studyFeaturesField $ StudyTerms (unStudyTermsKey studyFeaturesField) Nothing Nothing Nothing Nothing
|
||||||
oldFs <- selectKeysList
|
oldFs <- selectKeysList
|
||||||
([ StudyFeaturesUser ==. studyFeaturesUser
|
[ StudyFeaturesUser ==. studyFeaturesUser
|
||||||
, StudyFeaturesDegree ==. studyFeaturesDegree
|
, StudyFeaturesDegree ==. studyFeaturesDegree
|
||||||
, StudyFeaturesField ==. studyFeaturesField
|
, StudyFeaturesField ==. studyFeaturesField
|
||||||
, StudyFeaturesType ==. studyFeaturesType
|
, StudyFeaturesType ==. studyFeaturesType
|
||||||
, StudyFeaturesSemester ==. studyFeaturesSemester
|
, StudyFeaturesSemester ==. studyFeaturesSemester
|
||||||
])
|
]
|
||||||
[]
|
[]
|
||||||
case oldFs of
|
case oldFs of
|
||||||
[oldF] -> update oldF
|
[oldF] -> update oldF
|
||||||
@ -5073,20 +5056,20 @@ upsertCampusUser plugin ldapData = do
|
|||||||
associateUserSchoolsByTerms userId
|
associateUserSchoolsByTerms userId
|
||||||
|
|
||||||
let
|
let
|
||||||
userAssociatedSchools = fmap concat $ forM userAssociatedSchools' parseLdapSchools
|
userAssociatedSchools = concat <$> forM userAssociatedSchools' parseLdapSchools
|
||||||
userAssociatedSchools' = do
|
userAssociatedSchools' = do
|
||||||
(k, v) <- ldapData
|
(k, v) <- ldapData
|
||||||
guard $ k == ldapUserSchoolAssociation
|
guard $ k == ldapUserSchoolAssociation
|
||||||
v' <- v
|
v' <- v
|
||||||
Right str <- return $ Text.decodeUtf8' v'
|
Right str <- return $ Text.decodeUtf8' v'
|
||||||
return str
|
return str
|
||||||
|
|
||||||
ss <- either (throwM . CampusUserInvalidAssociatedSchools . tshow) return userAssociatedSchools
|
ss <- either (throwM . CampusUserInvalidAssociatedSchools . tshow) return userAssociatedSchools
|
||||||
|
|
||||||
forM_ ss $ \frag -> void . runMaybeT $ do
|
forM_ ss $ \frag -> void . runMaybeT $ do
|
||||||
let
|
let
|
||||||
exactMatch = MaybeT . getBy $ UniqueOrgUnit frag
|
exactMatch = MaybeT . getBy $ UniqueOrgUnit frag
|
||||||
infixMatch = (hoistMaybe . preview _head =<<) . lift . E.select . E.from $ \schoolLdap -> do
|
infixMatch = (hoistMaybe . preview _head) <=< (lift . E.select . E.from) $ \schoolLdap -> do
|
||||||
E.where_ $ E.val frag `E.isInfixOf` schoolLdap E.^. SchoolLdapOrgUnit
|
E.where_ $ E.val frag `E.isInfixOf` schoolLdap E.^. SchoolLdapOrgUnit
|
||||||
E.&&. E.not_ (E.isNothing $ schoolLdap E.^. SchoolLdapSchool)
|
E.&&. E.not_ (E.isNothing $ schoolLdap E.^. SchoolLdapSchool)
|
||||||
return schoolLdap
|
return schoolLdap
|
||||||
@ -5100,7 +5083,7 @@ upsertCampusUser plugin ldapData = do
|
|||||||
}
|
}
|
||||||
|
|
||||||
forM_ ss $ void . insertUnique . SchoolLdap Nothing
|
forM_ ss $ void . insertUnique . SchoolLdap Nothing
|
||||||
|
|
||||||
return user
|
return user
|
||||||
where
|
where
|
||||||
insertMaybe key val = get key >>= maybe (insert_ val) (\_ -> return ())
|
insertMaybe key val = get key >>= maybe (insert_ val) (\_ -> return ())
|
||||||
@ -5221,7 +5204,7 @@ instance YesodAuth UniWorX where
|
|||||||
_other -> return res
|
_other -> return res
|
||||||
|
|
||||||
$logDebugS "auth" $ tshow Creds{..}
|
$logDebugS "auth" $ tshow Creds{..}
|
||||||
UniWorX{ appSettings' = AppSettings{ appUserDefaults = UserDefaultConf{..}, ..}, .. } <- getYesod
|
UniWorX{..} <- getYesod
|
||||||
|
|
||||||
flip catches excHandlers $ case appLdapPool of
|
flip catches excHandlers $ case appLdapPool of
|
||||||
Just ldapPool
|
Just ldapPool
|
||||||
@ -5232,7 +5215,7 @@ instance YesodAuth UniWorX where
|
|||||||
_other
|
_other
|
||||||
-> acceptExisting
|
-> acceptExisting
|
||||||
|
|
||||||
authPlugins (UniWorX{ appSettings' = AppSettings{..}, appLdapPool }) = catMaybes
|
authPlugins UniWorX{ appSettings' = AppSettings{..}, appLdapPool } = catMaybes
|
||||||
[ flip campusLogin campusUserFailoverMode <$> appLdapPool
|
[ flip campusLogin campusUserFailoverMode <$> appLdapPool
|
||||||
, Just . hashLogin $ pwHashAlgorithm appAuthPWHash
|
, Just . hashLogin $ pwHashAlgorithm appAuthPWHash
|
||||||
, dummyLogin <$ guard appAuthDummyLogin
|
, dummyLogin <$ guard appAuthDummyLogin
|
||||||
@ -5262,7 +5245,7 @@ campusUserFailoverMode = FailoverUnlimited
|
|||||||
instance YesodAuthPersist UniWorX where
|
instance YesodAuthPersist UniWorX where
|
||||||
getAuthEntity = liftHandler . runDBRead . get
|
getAuthEntity = liftHandler . runDBRead . get
|
||||||
|
|
||||||
|
|
||||||
unsafeHandler :: UniWorX -> Handler a -> IO a
|
unsafeHandler :: UniWorX -> Handler a -> IO a
|
||||||
unsafeHandler f h = do
|
unsafeHandler f h = do
|
||||||
logger <- makeLogger f
|
logger <- makeLogger f
|
||||||
|
|||||||
@ -116,7 +116,7 @@ ordinalEN (toMessage -> numStr) = case lastChar of
|
|||||||
Just '3' -> [st|#{numStr}rd|]
|
Just '3' -> [st|#{numStr}rd|]
|
||||||
_other -> [st|#{numStr}th|]
|
_other -> [st|#{numStr}th|]
|
||||||
where
|
where
|
||||||
lastChar = last <$> fromNullable numStr
|
lastChar = last <$> fromNullable numStr
|
||||||
|
|
||||||
|
|
||||||
-- Convenience Type for Messages, since Yesod messages cannot deal with compound type identifiers
|
-- Convenience Type for Messages, since Yesod messages cannot deal with compound type identifiers
|
||||||
@ -178,7 +178,7 @@ instance RenderMessage UniWorX MsgLanguage where
|
|||||||
| ("de" : "DE" : _) <- lang' = mr MsgGermanGermany
|
| ("de" : "DE" : _) <- lang' = mr MsgGermanGermany
|
||||||
| ("de" : _) <- lang' = mr MsgGerman
|
| ("de" : _) <- lang' = mr MsgGerman
|
||||||
| ("en" : "EU" : _) <- lang' = mr MsgEnglishEurope
|
| ("en" : "EU" : _) <- lang' = mr MsgEnglishEurope
|
||||||
| ("en" : _) <- lang' = mr MsgEnglish
|
| ("en" : _) <- lang' = mr MsgEnglish
|
||||||
| otherwise = lang
|
| otherwise = lang
|
||||||
where
|
where
|
||||||
mr = renderMessage foundation $ lang : filter (/= lang) ls
|
mr = renderMessage foundation $ lang : filter (/= lang) ls
|
||||||
@ -255,7 +255,7 @@ instance RenderMessage UniWorX StudyDegreeTerm where
|
|||||||
where
|
where
|
||||||
mr :: RenderMessage UniWorX msg => msg -> Text
|
mr :: RenderMessage UniWorX msg => msg -> Text
|
||||||
mr = renderMessage foundation ls
|
mr = renderMessage foundation ls
|
||||||
|
|
||||||
newtype ShortStudyFieldType = ShortStudyFieldType StudyFieldType
|
newtype ShortStudyFieldType = ShortStudyFieldType StudyFieldType
|
||||||
embedRenderMessageVariant ''UniWorX ''ShortStudyFieldType ("Short" <>)
|
embedRenderMessageVariant ''UniWorX ''ShortStudyFieldType ("Short" <>)
|
||||||
|
|
||||||
@ -341,7 +341,7 @@ instance RenderMessage UniWorX UniWorXMessages where
|
|||||||
uniworxMessages :: [UniWorXMessage] -> UniWorXMessages
|
uniworxMessages :: [UniWorXMessage] -> UniWorXMessages
|
||||||
uniworxMessages = UniWorXMessages . map SomeMessage
|
uniworxMessages = UniWorXMessages . map SomeMessage
|
||||||
|
|
||||||
|
|
||||||
-- This instance is required to use forms. You can modify renderMessage to
|
-- This instance is required to use forms. You can modify renderMessage to
|
||||||
-- achieve customized and internationalized form validation messages.
|
-- achieve customized and internationalized form validation messages.
|
||||||
instance RenderMessage UniWorX FormMessage where
|
instance RenderMessage UniWorX FormMessage where
|
||||||
|
|||||||
@ -75,11 +75,11 @@ pattern CSubmissionR tid ssh csh shn cid ptn
|
|||||||
pattern CApplicationR :: TermId -> SchoolId -> CourseShorthand -> CryptoFileNameCourseApplication -> CourseApplicationR -> Route UniWorX
|
pattern CApplicationR :: TermId -> SchoolId -> CourseShorthand -> CryptoFileNameCourseApplication -> CourseApplicationR -> Route UniWorX
|
||||||
pattern CApplicationR tid ssh csh appId ptn
|
pattern CApplicationR tid ssh csh appId ptn
|
||||||
= CourseR tid ssh csh (CourseApplicationR appId ptn)
|
= CourseR tid ssh csh (CourseApplicationR appId ptn)
|
||||||
|
|
||||||
pattern CNewsR :: TermId -> SchoolId -> CourseShorthand -> CryptoUUIDCourseNews -> CourseNewsR -> Route UniWorX
|
pattern CNewsR :: TermId -> SchoolId -> CourseShorthand -> CryptoUUIDCourseNews -> CourseNewsR -> Route UniWorX
|
||||||
pattern CNewsR tid ssh csh nId ptn
|
pattern CNewsR tid ssh csh nId ptn
|
||||||
= CourseR tid ssh csh (CourseNewsR nId ptn)
|
= CourseR tid ssh csh (CourseNewsR nId ptn)
|
||||||
|
|
||||||
pattern CEventR :: TermId -> SchoolId -> CourseShorthand -> CryptoUUIDCourseEvent -> CourseEventR -> Route UniWorX
|
pattern CEventR :: TermId -> SchoolId -> CourseShorthand -> CryptoUUIDCourseEvent -> CourseEventR -> Route UniWorX
|
||||||
pattern CEventR tid ssh csh nId ptn
|
pattern CEventR tid ssh csh nId ptn
|
||||||
= CourseR tid ssh csh (CourseEventR nId ptn)
|
= CourseR tid ssh csh (CourseEventR nId ptn)
|
||||||
|
|||||||
@ -47,7 +47,7 @@ embedRenderMessage ''UniWorX ''ButtonAdminStudyTermsParents id
|
|||||||
instance Button UniWorX ButtonAdminStudyTermsParents where
|
instance Button UniWorX ButtonAdminStudyTermsParents where
|
||||||
btnClasses BtnParentCandidatesInfer = [BCIsButton, BCPrimary]
|
btnClasses BtnParentCandidatesInfer = [BCIsButton, BCPrimary]
|
||||||
btnClasses BtnParentCandidatesDeleteAll = [BCIsButton, BCDanger]
|
btnClasses BtnParentCandidatesDeleteAll = [BCIsButton, BCDanger]
|
||||||
|
|
||||||
data ButtonAdminStudyTermsStandalone
|
data ButtonAdminStudyTermsStandalone
|
||||||
= BtnStandaloneCandidatesDeleteRedundant
|
= BtnStandaloneCandidatesDeleteRedundant
|
||||||
| BtnStandaloneCandidatesDeleteAll
|
| BtnStandaloneCandidatesDeleteAll
|
||||||
@ -62,7 +62,7 @@ instance Button UniWorX ButtonAdminStudyTermsStandalone where
|
|||||||
btnClasses BtnStandaloneCandidatesDeleteRedundant = [BCIsButton, BCPrimary]
|
btnClasses BtnStandaloneCandidatesDeleteRedundant = [BCIsButton, BCPrimary]
|
||||||
btnClasses BtnStandaloneCandidatesDeleteAll = [BCIsButton, BCDanger]
|
btnClasses BtnStandaloneCandidatesDeleteAll = [BCIsButton, BCDanger]
|
||||||
|
|
||||||
|
|
||||||
{-# ANN postAdminFeaturesR ("HLint: ignore Redundant void" :: String) #-}
|
{-# ANN postAdminFeaturesR ("HLint: ignore Redundant void" :: String) #-}
|
||||||
getAdminFeaturesR, postAdminFeaturesR :: Handler Html
|
getAdminFeaturesR, postAdminFeaturesR :: Handler Html
|
||||||
getAdminFeaturesR = postAdminFeaturesR
|
getAdminFeaturesR = postAdminFeaturesR
|
||||||
@ -147,7 +147,7 @@ postAdminFeaturesR = do
|
|||||||
deleteWhere ([] :: [Filter StudyTermStandaloneCandidate])
|
deleteWhere ([] :: [Filter StudyTermStandaloneCandidate])
|
||||||
addMessageI Success MsgAllStandaloneIncidencesDeleted
|
addMessageI Success MsgAllStandaloneIncidencesDeleted
|
||||||
redirect AdminFeaturesR
|
redirect AdminFeaturesR
|
||||||
|
|
||||||
|
|
||||||
newStudyTermKeys <- fromMaybe [] <$> lookupSessionJson SessionNewStudyTerms
|
newStudyTermKeys <- fromMaybe [] <$> lookupSessionJson SessionNewStudyTerms
|
||||||
badStudyTermKeys <- lookupSessionJson SessionConflictingStudyTerms
|
badStudyTermKeys <- lookupSessionJson SessionConflictingStudyTerms
|
||||||
@ -208,7 +208,7 @@ postAdminFeaturesR = do
|
|||||||
infRedundantStandalone <- Candidates.removeRedundantStandalone
|
infRedundantStandalone <- Candidates.removeRedundantStandalone
|
||||||
unless (null infRedundantStandalone) . addMessageI Info . MsgRedundantStandaloneCandidatesRemoved $ length infRedundantStandalone
|
unless (null infRedundantStandalone) . addMessageI Info . MsgRedundantStandaloneCandidatesRemoved $ length infRedundantStandalone
|
||||||
return updated
|
return updated
|
||||||
|
|
||||||
let newKeys = catMaybes $ Map.elems updated
|
let newKeys = catMaybes $ Map.elems updated
|
||||||
unless (null newKeys) $ do
|
unless (null newKeys) $ do
|
||||||
setSessionJson SessionNewStudyTerms newKeys
|
setSessionJson SessionNewStudyTerms newKeys
|
||||||
@ -247,19 +247,19 @@ postAdminFeaturesR = do
|
|||||||
=> Lens' a (Maybe Text)
|
=> Lens' a (Maybe Text)
|
||||||
-> Getter (DBRow r) (Maybe Text)
|
-> Getter (DBRow r) (Maybe Text)
|
||||||
-> Getter (DBRow r) i
|
-> Getter (DBRow r) i
|
||||||
-> DBRow r
|
-> DBRow r
|
||||||
-> DBCell (MForm (HandlerFor UniWorX)) (FormResult (DBFormResult i a (DBRow r)))
|
-> DBCell (MForm (HandlerFor UniWorX)) (FormResult (DBFormResult i a (DBRow r)))
|
||||||
textInputCell lensRes lensDefault lensIndex = formCell id (return . view lensIndex)
|
textInputCell lensRes lensDefault lensIndex = formCell id (return . view lensIndex)
|
||||||
(\row _mkUnique -> bimap (fmap $ set lensRes . assertM (not . Text.null)) fvWidget
|
(\row _mkUnique -> bimap (fmap $ set lensRes . assertM (not . Text.null)) fvWidget
|
||||||
<$> mopt (textField & cfStrip) "" (Just $ row ^. lensDefault)
|
<$> mopt (textField & cfStrip) "" (Just $ row ^. lensDefault)
|
||||||
)
|
)
|
||||||
|
|
||||||
checkboxCell :: Ord i
|
checkboxCell :: Ord i
|
||||||
=> Lens' a Bool
|
=> Lens' a Bool
|
||||||
-> Getter (DBRow r) Bool
|
-> Getter (DBRow r) Bool
|
||||||
-> Getter (DBRow r) i
|
-> Getter (DBRow r) i
|
||||||
-> DBRow r
|
-> DBRow r
|
||||||
-> DBCell (MForm (HandlerFor UniWorX)) (FormResult (DBFormResult i a (DBRow r)))
|
-> DBCell (MForm (HandlerFor UniWorX)) (FormResult (DBFormResult i a (DBRow r)))
|
||||||
checkboxCell lensRes lensDefault lensIndex = formCell id (return . view lensIndex)
|
checkboxCell lensRes lensDefault lensIndex = formCell id (return . view lensIndex)
|
||||||
( \row _mkUnique -> bimap (fmap $ set lensRes) fvWidget
|
( \row _mkUnique -> bimap (fmap $ set lensRes) fvWidget
|
||||||
<$> mpopt checkBoxField "" (Just $ row ^. lensDefault)
|
<$> mpopt checkBoxField "" (Just $ row ^. lensDefault)
|
||||||
@ -306,7 +306,7 @@ postAdminFeaturesR = do
|
|||||||
( \row _mkUnique -> bimap (fmap $ set lensRes) fvWidget
|
( \row _mkUnique -> bimap (fmap $ set lensRes) fvWidget
|
||||||
<$> mopt degreeField "" (Just $ row ^. lensDefault)
|
<$> mopt degreeField "" (Just $ row ^. lensDefault)
|
||||||
)
|
)
|
||||||
|
|
||||||
fieldTypeCell :: Ord i
|
fieldTypeCell :: Ord i
|
||||||
=> Lens' a (Maybe StudyFieldType)
|
=> Lens' a (Maybe StudyFieldType)
|
||||||
-> Getter (DBRow r) (Maybe StudyFieldType)
|
-> Getter (DBRow r) (Maybe StudyFieldType)
|
||||||
@ -359,7 +359,7 @@ postAdminFeaturesR = do
|
|||||||
fieldSchools <- fmap (setOf $ folded . _Value) . E.select . E.from $ \school -> do
|
fieldSchools <- fmap (setOf $ folded . _Value) . E.select . E.from $ \school -> do
|
||||||
E.where_ . E.exists . E.from $ \schoolTerms ->
|
E.where_ . E.exists . E.from $ \schoolTerms ->
|
||||||
E.where_ $ schoolTerms E.^. SchoolTermsSchool E.==. school E.^. SchoolId
|
E.where_ $ schoolTerms E.^. SchoolTermsSchool E.==. school E.^. SchoolId
|
||||||
E.&&. schoolTerms E.^. SchoolTermsTerms E.==. E.val fId
|
E.&&. schoolTerms E.^. SchoolTermsTerms E.==. E.val fId
|
||||||
E.where_ $ school E.^. SchoolShorthand `E.in_` E.valList (toListOf (folded . _entityKey . _SchoolId) schools)
|
E.where_ $ school E.^. SchoolShorthand `E.in_` E.valList (toListOf (folded . _entityKey . _SchoolId) schools)
|
||||||
return $ school E.^. SchoolId
|
return $ school E.^. SchoolId
|
||||||
fieldParents <- fmap (setOf folded) . E.select . E.from $ \terms -> do
|
fieldParents <- fmap (setOf folded) . E.select . E.from $ \terms -> do
|
||||||
|
|||||||
@ -45,10 +45,10 @@ testDownloadForm = identifyForm FIDTestDownload . renderWForm FormStandard $ do
|
|||||||
|
|
||||||
maxSizeRes <- wreq intField (fslI MsgTestDownloadMaxSize) . Just $ 2 * 2^30
|
maxSizeRes <- wreq intField (fslI MsgTestDownloadMaxSize) . Just $ 2 * 2^30
|
||||||
modeRes <- wpopt (selectField optionsFinite) (fslI MsgTestDownloadMode) $ Just TestDownloadDirect
|
modeRes <- wpopt (selectField optionsFinite) (fslI MsgTestDownloadMode) $ Just TestDownloadDirect
|
||||||
|
|
||||||
return $ TestDownloadOptions
|
return $ TestDownloadOptions
|
||||||
<$> pure randomSeed
|
randomSeed
|
||||||
<*> maxSizeRes
|
<$> maxSizeRes
|
||||||
<*> pure (2^20)
|
<*> pure (2^20)
|
||||||
<*> modeRes
|
<*> modeRes
|
||||||
|
|
||||||
@ -86,7 +86,7 @@ testDownload = do
|
|||||||
sourceDBFiles = E.selectSource . E.from $ \fileContent -> do
|
sourceDBFiles = E.selectSource . E.from $ \fileContent -> do
|
||||||
E.orderBy [E.asc $ E.random_ @Int64]
|
E.orderBy [E.asc $ E.random_ @Int64]
|
||||||
return fileContent
|
return fileContent
|
||||||
|
|
||||||
takeLimit n | n <= 0 = return ()
|
takeLimit n | n <= 0 = return ()
|
||||||
takeLimit n = do
|
takeLimit n = do
|
||||||
c <- await
|
c <- await
|
||||||
|
|||||||
@ -30,7 +30,7 @@ bearerTokenForm :: WForm Handler (FormResult BearerTokenForm)
|
|||||||
bearerTokenForm = do
|
bearerTokenForm = do
|
||||||
muid <- maybeAuthId
|
muid <- maybeAuthId
|
||||||
mr <- getMessageRender
|
mr <- getMessageRender
|
||||||
|
|
||||||
btfAuthorityGroups <- aFormToWForm $ HashSet.fromList . map Left <$> massInputListA pathPieceField (const "") MsgBearerTokenAuthorityGroupMissing (\p -> Just . SomeRoute $ AdminTokensR :#: p) ("token-groups" :: Text) (fslI MsgBearerTokenAuthorityGroups & setTooltip MsgBearerTokenAuthorityGroupsTip) False Nothing
|
btfAuthorityGroups <- aFormToWForm $ HashSet.fromList . map Left <$> massInputListA pathPieceField (const "") MsgBearerTokenAuthorityGroupMissing (\p -> Just . SomeRoute $ AdminTokensR :#: p) ("token-groups" :: Text) (fslI MsgBearerTokenAuthorityGroups & setTooltip MsgBearerTokenAuthorityGroupsTip) False Nothing
|
||||||
btfAuthorityUsers <- fmap (fmap . ofoldMap $ HashSet.singleton . Right) <$> wopt (checkMap (foldMapM $ fmap Set.singleton . left MsgBearerTokenAuthorityUnknownUser) (Set.map Right) $ multiUserField False Nothing) (fslpI MsgBearerTokenAuthorityUsers (mr MsgLdapIdentificationOrEmail) & setTooltip MsgBearerTokenAuthorityUsersTip) (Just $ Set.singleton <$> muid)
|
btfAuthorityUsers <- fmap (fmap . ofoldMap $ HashSet.singleton . Right) <$> wopt (checkMap (foldMapM $ fmap Set.singleton . left MsgBearerTokenAuthorityUnknownUser) (Set.map Right) $ multiUserField False Nothing) (fslpI MsgBearerTokenAuthorityUsers (mr MsgLdapIdentificationOrEmail) & setTooltip MsgBearerTokenAuthorityUsersTip) (Just $ Set.singleton <$> muid)
|
||||||
let btfAuthority' :: FormResult (HashSet (Either UserGroupName UserId))
|
let btfAuthority' :: FormResult (HashSet (Either UserGroupName UserId))
|
||||||
@ -58,7 +58,7 @@ bearerTokenForm = do
|
|||||||
|
|
||||||
miLayout' :: MassInputLayout ListLength (Route UniWorX, Value) (Route UniWorX, Value)
|
miLayout' :: MassInputLayout ListLength (Route UniWorX, Value) (Route UniWorX, Value)
|
||||||
miLayout' lLength _ cellWdgts delButtons addWdgts = $(widgetFile "widgets/massinput/token-restrictions/layout")
|
miLayout' lLength _ cellWdgts delButtons addWdgts = $(widgetFile "widgets/massinput/token-restrictions/layout")
|
||||||
|
|
||||||
btfRestrict' <- fmap HashMap.fromList <$> btfRestrictForm
|
btfRestrict' <- fmap HashMap.fromList <$> btfRestrictForm
|
||||||
|
|
||||||
btfAddAuth' <- fmap (assertM $ not . Set.null . dnfTerms) <$> wopt pathPieceField (fslI MsgBearerTokenAdditionalAuth & setTooltip MsgBearerTokenAdditionalAuthTip) Nothing
|
btfAddAuth' <- fmap (assertM $ not . Set.null . dnfTerms) <$> wopt pathPieceField (fslI MsgBearerTokenAdditionalAuth & setTooltip MsgBearerTokenAdditionalAuthTip) Nothing
|
||||||
@ -87,7 +87,7 @@ postAdminTokensR = do
|
|||||||
& HashSet.map (left toJSON)
|
& HashSet.map (left toJSON)
|
||||||
|
|
||||||
fmap Just . encodeBearer . set _bearerRestrictions btfRestrict =<< bearerToken btfAuthority' btfRoutes btfAddAuth btfExpiresAt btfStartsAt
|
fmap Just . encodeBearer . set _bearerRestrictions btfRestrict =<< bearerToken btfAuthority' btfRoutes btfAddAuth btfExpiresAt btfStartsAt
|
||||||
|
|
||||||
siteLayoutMsg' MsgMenuAdminTokens $ do
|
siteLayoutMsg' MsgMenuAdminTokens $ do
|
||||||
setTitleI MsgMenuAdminTokens
|
setTitleI MsgMenuAdminTokens
|
||||||
|
|
||||||
|
|||||||
@ -33,7 +33,7 @@ newtype SessionDataAllocationResults = SessionDataAllocationResults
|
|||||||
deriving (Monoid, Semigroup) via Dual (Map (TermId, SchoolId, AllocationShorthand) (UTCTime, AllocationFingerprint, Set (UserId, CourseId), Seq MatchingLogRun))
|
deriving (Monoid, Semigroup) via Dual (Map (TermId, SchoolId, AllocationShorthand) (UTCTime, AllocationFingerprint, Set (UserId, CourseId), Seq MatchingLogRun))
|
||||||
|
|
||||||
makeWrapped ''SessionDataAllocationResults
|
makeWrapped ''SessionDataAllocationResults
|
||||||
|
|
||||||
|
|
||||||
data AllocationAcceptButton
|
data AllocationAcceptButton
|
||||||
= BtnAllocationAccept
|
= BtnAllocationAccept
|
||||||
@ -59,7 +59,7 @@ allocationAcceptForm aId = runMaybeT $ do
|
|||||||
let applications = E.subSelectCount . E.from $ \courseApplication ->
|
let applications = E.subSelectCount . E.from $ \courseApplication ->
|
||||||
E.where_ $ courseApplication E.^. CourseApplicationAllocation E.==. E.val (Just aId)
|
E.where_ $ courseApplication E.^. CourseApplicationAllocation E.==. E.val (Just aId)
|
||||||
E.&&. courseApplication E.^. CourseApplicationUser E.==. allocationUser E.^. AllocationUserUser
|
E.&&. courseApplication E.^. CourseApplicationUser E.==. allocationUser E.^. AllocationUserUser
|
||||||
return . (allocationUser E.^. AllocationUserUser, ) $ E.case_
|
return . (allocationUser E.^. AllocationUserUser, ) $ E.case_
|
||||||
[ E.when_ (E.castNum (allocationUser E.^. AllocationUserTotalCourses) E.>. applications)
|
[ E.when_ (E.castNum (allocationUser E.^. AllocationUserTotalCourses) E.>. applications)
|
||||||
E.then_ (applications :: E.SqlExpr (E.Value Int))
|
E.then_ (applications :: E.SqlExpr (E.Value Int))
|
||||||
]
|
]
|
||||||
@ -124,7 +124,7 @@ allocationAcceptForm aId = runMaybeT $ do
|
|||||||
= invDualHeat (optimumAllocated capN) capN
|
= invDualHeat (optimumAllocated capN) capN
|
||||||
degenerateHeat capN
|
degenerateHeat capN
|
||||||
= capN <= optimumAllocated capN
|
= capN <= optimumAllocated capN
|
||||||
|
|
||||||
return (prevAllocMatches, $(widgetFile "allocation/accept"))
|
return (prevAllocMatches, $(widgetFile "allocation/accept"))
|
||||||
|
|
||||||
getAAcceptR, postAAcceptR :: TermId -> SchoolId -> AllocationShorthand -> Handler Html
|
getAAcceptR, postAAcceptR :: TermId -> SchoolId -> AllocationShorthand -> Handler Html
|
||||||
@ -135,7 +135,7 @@ postAAcceptR tid ssh ash = do
|
|||||||
|
|
||||||
acceptForm <- maybe (redirect $ AllocationR tid ssh ash AComputeR) return =<< allocationAcceptForm aId
|
acceptForm <- maybe (redirect $ AllocationR tid ssh ash AComputeR) return =<< allocationAcceptForm aId
|
||||||
|
|
||||||
formRes@((acceptRes, _), _) <- liftHandler $ runFormPost acceptForm
|
formRes@((acceptRes, _), _) <- liftHandler $ runFormPost acceptForm
|
||||||
|
|
||||||
didStore <- formResultMaybe acceptRes $ \(now, allocFp, allocMatchings, allocLog) -> do
|
didStore <- formResultMaybe acceptRes $ \(now, allocFp, allocMatchings, allocLog) -> do
|
||||||
modifySessionJson SessionAllocationResults . fmap (assertM $ not . views _Wrapped onull) . over (mapped . _Wrapped :: Setter' (Maybe SessionDataAllocationResults) _) $
|
modifySessionJson SessionAllocationResults . fmap (assertM $ not . views _Wrapped onull) . over (mapped . _Wrapped :: Setter' (Maybe SessionDataAllocationResults) _) $
|
||||||
|
|||||||
@ -58,24 +58,24 @@ data ApplicationFormMode = ApplicationFormMode
|
|||||||
, afmApplicantEdit :: Bool -- ^ Allow editing text, files, priority (if shown)
|
, afmApplicantEdit :: Bool -- ^ Allow editing text, files, priority (if shown)
|
||||||
, afmLecturer :: Bool -- ^ Allow editing rating
|
, afmLecturer :: Bool -- ^ Allow editing rating
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
data ApplicationFormException = ApplicationFormNoApplication -- ^ Could not fill forced fields of application form with data from application
|
data ApplicationFormException = ApplicationFormNoApplication -- ^ Could not fill forced fields of application form with data from application
|
||||||
deriving (Eq, Ord, Read, Show, Generic, Typeable)
|
deriving (Eq, Ord, Read, Show, Generic, Typeable)
|
||||||
instance Exception ApplicationFormException
|
instance Exception ApplicationFormException
|
||||||
|
|
||||||
applicationForm :: (Maybe AllocationId)
|
applicationForm :: Maybe AllocationId
|
||||||
-> CourseId
|
-> CourseId
|
||||||
-> UserId
|
-> UserId
|
||||||
-> ApplicationFormMode -- ^ Which parts of the shared form to display
|
-> ApplicationFormMode -- ^ Which parts of the shared form to display
|
||||||
-> Html -> MForm Handler (FormResult ApplicationForm, ApplicationFormView)
|
-> Html -> MForm Handler (FormResult ApplicationForm, ApplicationFormView)
|
||||||
applicationForm maId@(is _Just -> isAlloc) cid uid ApplicationFormMode{..} csrf = do
|
applicationForm maId@(is _Just -> isAlloc) cid uid ApplicationFormMode{..} csrf = do
|
||||||
|
|
||||||
(mApp, coursesNum, Course{..}, maxPrio) <- liftHandler . runDB $ do
|
(mApp, coursesNum, Course{..}, maxPrio) <- liftHandler . runDB $ do
|
||||||
mApplication <- listToMaybe <$> selectList [CourseApplicationAllocation ==. maId, CourseApplicationUser ==. uid, CourseApplicationCourse ==. cid] [LimitTo 1]
|
mApplication <- listToMaybe <$> selectList [CourseApplicationAllocation ==. maId, CourseApplicationUser ==. uid, CourseApplicationCourse ==. cid] [LimitTo 1]
|
||||||
coursesNum <- fromIntegral . fromMaybe 1 <$> for maId (\aId -> count [AllocationCourseAllocation ==. aId])
|
coursesNum <- fromIntegral . fromMaybe 1 <$> for maId (\aId -> count [AllocationCourseAllocation ==. aId])
|
||||||
course <- getJust cid
|
course <- getJust cid
|
||||||
(fromMaybe 0 -> maxPrio) <- fmap ((>>= E.unValue) . listToMaybe) . E.select . E.from $ \courseApplication -> do
|
(fromMaybe 0 -> maxPrio) <- fmap (E.unValue <=< listToMaybe) . E.select . E.from $ \courseApplication -> do
|
||||||
E.where_ $ courseApplication E.^. CourseApplicationUser E.==. E.val uid
|
E.where_ $ courseApplication E.^. CourseApplicationUser E.==. E.val uid
|
||||||
E.&&. courseApplication E.^. CourseApplicationAllocation E.==. E.val maId
|
E.&&. courseApplication E.^. CourseApplicationAllocation E.==. E.val maId
|
||||||
E.&&. E.not_ (E.isNothing $ courseApplication E.^. CourseApplicationAllocationPriority)
|
E.&&. E.not_ (E.isNothing $ courseApplication E.^. CourseApplicationAllocationPriority)
|
||||||
@ -91,25 +91,25 @@ applicationForm maId@(is _Just -> isAlloc) cid uid ApplicationFormMode{..} csrf
|
|||||||
|
|
||||||
mkPrioOption :: Natural -> Option Natural
|
mkPrioOption :: Natural -> Option Natural
|
||||||
mkPrioOption i = Option
|
mkPrioOption i = Option
|
||||||
{ optionDisplay = mr . MsgAllocationCoursePriority $ coursesNum' - i
|
{ optionDisplay = mr . MsgAllocationCoursePriority $ coursesNum' - i
|
||||||
, optionInternalValue = i
|
, optionInternalValue = i
|
||||||
, optionExternalValue = tshow i
|
, optionExternalValue = tshow i
|
||||||
}
|
}
|
||||||
|
|
||||||
prioOptions :: OptionList Natural
|
prioOptions :: OptionList Natural
|
||||||
prioOptions = OptionList
|
prioOptions = OptionList
|
||||||
{ olOptions = sortOn (Down . optionInternalValue) . map mkPrioOption $ [0 .. pred coursesNum']
|
{ olOptions = sortOn (Down . optionInternalValue) . map mkPrioOption $ [0 .. pred coursesNum']
|
||||||
, olReadExternal = readMay
|
, olReadExternal = readMay
|
||||||
}
|
}
|
||||||
prioField = selectField' (Just $ SomeMessage MsgAllocationCourseNoApplication) $ return prioOptions
|
prioField = selectField' (Just $ SomeMessage MsgAllocationCourseNoApplication) $ return prioOptions
|
||||||
|
|
||||||
(prioRes, prioView) <- case (isAlloc, afmApplicant, afmApplicantEdit, mApp) of
|
(prioRes, prioView) <- case (isAlloc, afmApplicant, afmApplicantEdit, mApp) of
|
||||||
(True , True , True , Nothing)
|
(True , True , True , Nothing)
|
||||||
-> over _2 Just <$> mopt prioField (fslI MsgApplicationPriority) (Just $ oldPrio)
|
-> over _2 Just <$> mopt prioField (fslI MsgApplicationPriority) (Just oldPrio)
|
||||||
(True , True , True , Just _ )
|
(True , True , True , Just _ )
|
||||||
-> over (_1 . _FormSuccess) Just . over _2 Just <$> mreq prioField (fslI MsgApplicationPriority) oldPrio
|
-> over (_1 . _FormSuccess) Just . over _2 Just <$> mreq prioField (fslI MsgApplicationPriority) oldPrio
|
||||||
(True , True , False, _ )
|
(True , True , False, _ )
|
||||||
-> over _2 Just <$> mforcedOpt prioField (fslI MsgApplicationPriority) oldPrio
|
-> over _2 Just <$> mforcedOpt prioField (fslI MsgApplicationPriority) oldPrio
|
||||||
(True , False, _ , Just _ )
|
(True , False, _ , Just _ )
|
||||||
| is _Just oldPrio
|
| is _Just oldPrio
|
||||||
-> pure (FormSuccess oldPrio, Nothing)
|
-> pure (FormSuccess oldPrio, Nothing)
|
||||||
@ -144,7 +144,7 @@ applicationForm maId@(is _Just -> isAlloc) cid uid ApplicationFormMode{..} csrf
|
|||||||
let appFilesInfo = (,) <$> hasFiles <*> appCID
|
let appFilesInfo = (,) <$> hasFiles <*> appCID
|
||||||
|
|
||||||
filesLinkView <- if
|
filesLinkView <- if
|
||||||
| fromMaybe False hasFiles || (isn't _NoUpload courseApplicationsFiles && not afmApplicantEdit)
|
| Just True == hasFiles || (isn't _NoUpload courseApplicationsFiles && not afmApplicantEdit)
|
||||||
-> let filesLinkField = Field{..}
|
-> let filesLinkField = Field{..}
|
||||||
where
|
where
|
||||||
fieldParse _ _ = return $ Right Nothing
|
fieldParse _ _ = return $ Right Nothing
|
||||||
@ -165,7 +165,7 @@ applicationForm maId@(is _Just -> isAlloc) cid uid ApplicationFormMode{..} csrf
|
|||||||
-> return Nothing
|
-> return Nothing
|
||||||
|
|
||||||
filesWarningView <- if
|
filesWarningView <- if
|
||||||
| fromMaybe False hasFiles && isn't _NoUpload courseApplicationsFiles && afmApplicantEdit
|
| Just True == hasFiles && isn't _NoUpload courseApplicationsFiles && afmApplicantEdit
|
||||||
-> fmap (Just . snd) . formMessage =<< messageIconI Info IconFileUpload MsgCourseApplicationFilesNeedReupload
|
-> fmap (Just . snd) . formMessage =<< messageIconI Info IconFileUpload MsgCourseApplicationFilesNeedReupload
|
||||||
| otherwise
|
| otherwise
|
||||||
-> return Nothing
|
-> return Nothing
|
||||||
@ -174,16 +174,16 @@ applicationForm maId@(is _Just -> isAlloc) cid uid ApplicationFormMode{..} csrf
|
|||||||
let mkFs = bool MsgCourseApplicationFile MsgCourseApplicationArchive
|
let mkFs = bool MsgCourseApplicationFile MsgCourseApplicationArchive
|
||||||
in if
|
in if
|
||||||
| not afmApplicantEdit || is _NoUpload courseApplicationsFiles
|
| not afmApplicantEdit || is _NoUpload courseApplicationsFiles
|
||||||
-> return $ (FormSuccess Nothing, Nothing)
|
-> return (FormSuccess Nothing, Nothing)
|
||||||
| otherwise
|
| otherwise
|
||||||
-> fmap (over _2 $ Just . ($ [])) . aFormToForm $ fileUploadForm False (fslI . mkFs) courseApplicationsFiles
|
-> fmap (over _2 $ Just . ($ [])) . aFormToForm $ fileUploadForm False (fslI . mkFs) courseApplicationsFiles
|
||||||
|
|
||||||
(vetoRes, vetoView) <- if
|
(vetoRes, vetoView) <- if
|
||||||
| afmLecturer
|
| afmLecturer
|
||||||
-> over _2 Just <$> mpopt checkBoxField (fslI MsgApplicationVeto & setTooltip MsgApplicationVetoTip) (Just . fromMaybe False $ courseApplicationRatingVeto . entityVal <$> mApp)
|
-> over _2 Just <$> mpopt checkBoxField (fslI MsgApplicationVeto & setTooltip MsgApplicationVetoTip) (Just $ Just True == fmap (courseApplicationRatingVeto . entityVal) mApp)
|
||||||
| otherwise
|
| otherwise
|
||||||
-> return (FormSuccess . fromMaybe False $ courseApplicationRatingVeto . entityVal <$> mApp, Nothing)
|
-> return (FormSuccess $ Just True == fmap (courseApplicationRatingVeto . entityVal) mApp, Nothing)
|
||||||
|
|
||||||
(pointsRes, pointsView) <- if
|
(pointsRes, pointsView) <- if
|
||||||
| afmLecturer
|
| afmLecturer
|
||||||
-> over _2 Just <$> mopt examGradeField (fslI MsgApplicationRatingPoints & setTooltip MsgApplicationRatingPointsTip) (fmap Just $ mApp >>= courseApplicationRatingPoints . entityVal)
|
-> over _2 Just <$> mopt examGradeField (fslI MsgApplicationRatingPoints & setTooltip MsgApplicationRatingPointsTip) (fmap Just $ mApp >>= courseApplicationRatingPoints . entityVal)
|
||||||
@ -195,7 +195,7 @@ applicationForm maId@(is _Just -> isAlloc) cid uid ApplicationFormMode{..} csrf
|
|||||||
-> over _2 Just . over (_1 . _FormSuccess) (assertM $ not . Text.null) <$> mopt textField' (fslI MsgApplicationRatingComment & setTooltip (bool MsgApplicationRatingCommentInvisibleTip MsgApplicationRatingCommentVisibleTip courseApplicationsRatingsVisible)) (fmap Just $ mApp >>= courseApplicationRatingComment . entityVal)
|
-> over _2 Just . over (_1 . _FormSuccess) (assertM $ not . Text.null) <$> mopt textField' (fslI MsgApplicationRatingComment & setTooltip (bool MsgApplicationRatingCommentInvisibleTip MsgApplicationRatingCommentVisibleTip courseApplicationsRatingsVisible)) (fmap Just $ mApp >>= courseApplicationRatingComment . entityVal)
|
||||||
| otherwise
|
| otherwise
|
||||||
-> return (FormSuccess $ courseApplicationRatingComment . entityVal =<< mApp, Nothing)
|
-> return (FormSuccess $ courseApplicationRatingComment . entityVal =<< mApp, Nothing)
|
||||||
|
|
||||||
let
|
let
|
||||||
buttons = catMaybes
|
buttons = catMaybes
|
||||||
[ guardOn (not afmApplicantEdit && is _Just mApp && afmLecturer) BtnAllocationApplicationRate
|
[ guardOn (not afmApplicantEdit && is _Just mApp && afmLecturer) BtnAllocationApplicationRate
|
||||||
@ -225,7 +225,7 @@ applicationForm maId@(is _Just -> isAlloc) cid uid ApplicationFormMode{..} csrf
|
|||||||
<*> actionRes
|
<*> actionRes
|
||||||
, ApplicationFormView
|
, ApplicationFormView
|
||||||
{ afvPriority = prioView
|
{ afvPriority = prioView
|
||||||
, afvForm = catMaybes $
|
, afvForm = catMaybes $
|
||||||
[ Just fieldView'
|
[ Just fieldView'
|
||||||
, textView
|
, textView
|
||||||
, filesLinkView
|
, filesLinkView
|
||||||
@ -240,7 +240,7 @@ applicationForm maId@(is _Just -> isAlloc) cid uid ApplicationFormMode{..} csrf
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
editApplicationR :: Maybe AllocationId
|
editApplicationR :: Maybe AllocationId
|
||||||
@ -285,7 +285,7 @@ editApplicationR maId uid cid mAppId afMode allowAction postAction = do
|
|||||||
, courseApplicationRatingTime = guardOn rated now
|
, courseApplicationRatingTime = guardOn rated now
|
||||||
}
|
}
|
||||||
|
|
||||||
runConduit $ transPipe liftHandler (traverse_ id afFiles) .| C.mapM_ (insert_ . review _FileReference . (, CourseApplicationFileResidual appId))
|
runConduit $ transPipe liftHandler (sequence_ afFiles) .| C.mapM_ (insert_ . review _FileReference . (, CourseApplicationFileResidual appId))
|
||||||
audit $ TransactionCourseApplicationEdit cid uid appId
|
audit $ TransactionCourseApplicationEdit cid uid appId
|
||||||
addMessageI Success $ MsgCourseApplicationCreated courseShorthand
|
addMessageI Success $ MsgCourseApplicationCreated courseShorthand
|
||||||
| is _BtnAllocationApplicationEdit afAction || is _BtnAllocationApplicationRate afAction
|
| is _BtnAllocationApplicationEdit afAction || is _BtnAllocationApplicationRate afAction
|
||||||
@ -354,7 +354,7 @@ editApplicationR maId uid cid mAppId afMode allowAction postAction = do
|
|||||||
redirect postAction
|
redirect postAction
|
||||||
|
|
||||||
return (appView, appEnc)
|
return (appView, appEnc)
|
||||||
|
|
||||||
|
|
||||||
postAApplyR :: TermId -> SchoolId -> AllocationShorthand -> CryptoUUIDCourse -> Handler Void
|
postAApplyR :: TermId -> SchoolId -> AllocationShorthand -> CryptoUUIDCourse -> Handler Void
|
||||||
postAApplyR tid ssh ash cID = do
|
postAApplyR tid ssh ash cID = do
|
||||||
|
|||||||
@ -62,7 +62,7 @@ missingPriorities aId = wFormToAForm $ do
|
|||||||
missingPriosFieldView theId name attrs res isReq
|
missingPriosFieldView theId name attrs res isReq
|
||||||
= $(i18nWidgetFile "allocation-confirm-missing-prios")
|
= $(i18nWidgetFile "allocation-confirm-missing-prios")
|
||||||
where checkBoxFieldView = labeledCheckBoxView (i18n MsgAllocationUsersMissingPrioritiesOk) theId name attrs res isReq
|
where checkBoxFieldView = labeledCheckBoxView (i18n MsgAllocationUsersMissingPrioritiesOk) theId name attrs res isReq
|
||||||
|
|
||||||
if
|
if
|
||||||
| null usersWithoutPrio
|
| null usersWithoutPrio
|
||||||
-> return $ pure Set.empty
|
-> return $ pure Set.empty
|
||||||
|
|||||||
@ -58,7 +58,7 @@ resultApplied = _dbrOutput . _3
|
|||||||
|
|
||||||
allocationTermLink :: TermId -> SomeRoute UniWorX
|
allocationTermLink :: TermId -> SomeRoute UniWorX
|
||||||
allocationTermLink tid = SomeRoute (AllocationListR, [(dbFilterKey allocationListIdent "term", toPathPiece tid)])
|
allocationTermLink tid = SomeRoute (AllocationListR, [(dbFilterKey allocationListIdent "term", toPathPiece tid)])
|
||||||
|
|
||||||
allocationSchoolLink :: SchoolId -> SomeRoute UniWorX
|
allocationSchoolLink :: SchoolId -> SomeRoute UniWorX
|
||||||
allocationSchoolLink ssh = SomeRoute (AllocationListR, [(dbFilterKey allocationListIdent "school", toPathPiece ssh)])
|
allocationSchoolLink ssh = SomeRoute (AllocationListR, [(dbFilterKey allocationListIdent "school", toPathPiece ssh)])
|
||||||
|
|
||||||
|
|||||||
@ -26,7 +26,7 @@ instance Finite AllocationPrioritiesMode
|
|||||||
nullaryPathPiece ''AllocationPrioritiesMode $ camelToPathPiece' 2
|
nullaryPathPiece ''AllocationPrioritiesMode $ camelToPathPiece' 2
|
||||||
|
|
||||||
embedRenderMessage ''UniWorX ''AllocationPrioritiesMode id
|
embedRenderMessage ''UniWorX ''AllocationPrioritiesMode id
|
||||||
|
|
||||||
|
|
||||||
getAPriosR, postAPriosR :: TermId -> SchoolId -> AllocationShorthand -> Handler Html
|
getAPriosR, postAPriosR :: TermId -> SchoolId -> AllocationShorthand -> Handler Html
|
||||||
getAPriosR = postAPriosR
|
getAPriosR = postAPriosR
|
||||||
@ -37,7 +37,7 @@ postAPriosR tid ssh ash = do
|
|||||||
numericPrios <- E.selectCountRows . E.from $ \allocationUser -> do
|
numericPrios <- E.selectCountRows . E.from $ \allocationUser -> do
|
||||||
E.where_ $ allocationUser E.^. AllocationUserAllocation E.==. E.val aId
|
E.where_ $ allocationUser E.^. AllocationUserAllocation E.==. E.val aId
|
||||||
E.where_ . E.maybe E.false sqlAllocationPriorityNumeric $ allocationUser E.^. AllocationUserPriority
|
E.where_ . E.maybe E.false sqlAllocationPriorityNumeric $ allocationUser E.^. AllocationUserPriority
|
||||||
|
|
||||||
ordinalPrios <- E.selectCountRows . E.from $ \allocationUser -> do
|
ordinalPrios <- E.selectCountRows . E.from $ \allocationUser -> do
|
||||||
E.where_ $ allocationUser E.^. AllocationUserAllocation E.==. E.val aId
|
E.where_ $ allocationUser E.^. AllocationUserAllocation E.==. E.val aId
|
||||||
E.where_ . E.maybe E.false (E.not_ . sqlAllocationPriorityNumeric) $ allocationUser E.^. AllocationUserPriority
|
E.where_ . E.maybe E.false (E.not_ . sqlAllocationPriorityNumeric) $ allocationUser E.^. AllocationUserPriority
|
||||||
@ -59,7 +59,7 @@ postAPriosR tid ssh ash = do
|
|||||||
let sourcePrios = case mode of
|
let sourcePrios = case mode of
|
||||||
AllocationPrioritiesNumeric -> transPipe liftHandler fInfo .| fileSourceCsvPositional Csv.NoHeader
|
AllocationPrioritiesNumeric -> transPipe liftHandler fInfo .| fileSourceCsvPositional Csv.NoHeader
|
||||||
AllocationPrioritiesOrdinal -> transPipe liftHandler fInfo .| fileSourceCsvPositional Csv.NoHeader .| C.map Csv.fromOnly .| ordinalPriorities
|
AllocationPrioritiesOrdinal -> transPipe liftHandler fInfo .| fileSourceCsvPositional Csv.NoHeader .| C.map Csv.fromOnly .| ordinalPriorities
|
||||||
|
|
||||||
(matrSunk, matrMissing) <- runDB $ do
|
(matrSunk, matrMissing) <- runDB $ do
|
||||||
Entity aId _ <- getBy404 $ TermSchoolAllocationShort tid ssh ash
|
Entity aId _ <- getBy404 $ TermSchoolAllocationShort tid ssh ash
|
||||||
updateWhere
|
updateWhere
|
||||||
@ -77,7 +77,7 @@ postAPriosR tid ssh ash = do
|
|||||||
E.&&. courseApplication E.^. CourseApplicationAllocation E.==. E.just (E.val aId)
|
E.&&. courseApplication E.^. CourseApplicationAllocation E.==. E.just (E.val aId)
|
||||||
return (matrSunk, matrMissing)
|
return (matrSunk, matrMissing)
|
||||||
|
|
||||||
when (matrSunk > 0) $
|
when (matrSunk > 0) $
|
||||||
addMessageI Success $ MsgAllocationPrioritiesSunk matrSunk
|
addMessageI Success $ MsgAllocationPrioritiesSunk matrSunk
|
||||||
when (matrMissing > 0) $
|
when (matrMissing > 0) $
|
||||||
addMessageI Error $ MsgAllocationPrioritiesMissing matrMissing
|
addMessageI Error $ MsgAllocationPrioritiesMissing matrMissing
|
||||||
|
|||||||
@ -46,7 +46,7 @@ postARegisterR tid ssh ash = do
|
|||||||
formResult registerRes $ \AllocationRegisterForm{..} -> runDB $ do
|
formResult registerRes $ \AllocationRegisterForm{..} -> runDB $ do
|
||||||
aId <- getKeyBy404 $ TermSchoolAllocationShort tid ssh ash
|
aId <- getKeyBy404 $ TermSchoolAllocationShort tid ssh ash
|
||||||
isRegistered <- existsBy $ UniqueAllocationUser aId uid
|
isRegistered <- existsBy $ UniqueAllocationUser aId uid
|
||||||
void $ upsert AllocationUser
|
void $ upsert AllocationUser
|
||||||
{ allocationUserAllocation = aId
|
{ allocationUserAllocation = aId
|
||||||
, allocationUserUser = uid
|
, allocationUserUser = uid
|
||||||
, allocationUserTotalCourses = arfTotalCourses
|
, allocationUserTotalCourses = arfTotalCourses
|
||||||
@ -57,5 +57,5 @@ postARegisterR tid ssh ash = do
|
|||||||
if
|
if
|
||||||
| isRegistered -> addMessageI Success MsgAllocationRegistrationEdited
|
| isRegistered -> addMessageI Success MsgAllocationRegistrationEdited
|
||||||
| otherwise -> addMessageI Success MsgAllocationRegistered
|
| otherwise -> addMessageI Success MsgAllocationRegistered
|
||||||
|
|
||||||
redirect $ AllocationR tid ssh ash AShowR :#: ("allocation-participation" :: Text)
|
redirect $ AllocationR tid ssh ash AShowR :#: ("allocation-participation" :: Text)
|
||||||
|
|||||||
@ -7,7 +7,7 @@ import Import
|
|||||||
import Utils.Course
|
import Utils.Course
|
||||||
|
|
||||||
import Handler.Utils
|
import Handler.Utils
|
||||||
|
|
||||||
import Handler.Allocation.Register
|
import Handler.Allocation.Register
|
||||||
import Handler.Allocation.Application
|
import Handler.Allocation.Application
|
||||||
|
|
||||||
|
|||||||
@ -63,11 +63,11 @@ type UserTableData = DBRow ( Entity User
|
|||||||
, Int -- ^ Applied
|
, Int -- ^ Applied
|
||||||
, Int -- ^ Assigned
|
, Int -- ^ Assigned
|
||||||
, Int -- ^ Vetoed
|
, Int -- ^ Vetoed
|
||||||
)
|
)
|
||||||
|
|
||||||
resultUser :: Lens' UserTableData (Entity User)
|
resultUser :: Lens' UserTableData (Entity User)
|
||||||
resultUser = _dbrOutput . _1
|
resultUser = _dbrOutput . _1
|
||||||
|
|
||||||
resultAllocationUser :: Lens' UserTableData (Entity AllocationUser)
|
resultAllocationUser :: Lens' UserTableData (Entity AllocationUser)
|
||||||
resultAllocationUser = _dbrOutput . _2
|
resultAllocationUser = _dbrOutput . _2
|
||||||
|
|
||||||
@ -83,7 +83,7 @@ data AllocationUserTableCsv = AllocationUserTableCsv
|
|||||||
, csvAUserName :: Text
|
, csvAUserName :: Text
|
||||||
, csvAUserMatriculation :: Maybe Text
|
, csvAUserMatriculation :: Maybe Text
|
||||||
, csvAUserRequested
|
, csvAUserRequested
|
||||||
, csvAUserApplied
|
, csvAUserApplied
|
||||||
, csvAUserVetos
|
, csvAUserVetos
|
||||||
, csvAUserAssigned :: Natural
|
, csvAUserAssigned :: Natural
|
||||||
, csvAUserPriority :: Maybe AllocationPriority
|
, csvAUserPriority :: Maybe AllocationPriority
|
||||||
@ -94,10 +94,10 @@ allocationUserTableCsvOptions :: Csv.Options
|
|||||||
allocationUserTableCsvOptions = Csv.defaultOptions { Csv.fieldLabelModifier = camelToPathPiece' 3}
|
allocationUserTableCsvOptions = Csv.defaultOptions { Csv.fieldLabelModifier = camelToPathPiece' 3}
|
||||||
|
|
||||||
instance Csv.ToNamedRecord AllocationUserTableCsv where
|
instance Csv.ToNamedRecord AllocationUserTableCsv where
|
||||||
toNamedRecord = Csv.genericToNamedRecord allocationUserTableCsvOptions
|
toNamedRecord = Csv.genericToNamedRecord allocationUserTableCsvOptions
|
||||||
|
|
||||||
instance Csv.DefaultOrdered AllocationUserTableCsv where
|
instance Csv.DefaultOrdered AllocationUserTableCsv where
|
||||||
headerOrder = Csv.genericHeaderOrder allocationUserTableCsvOptions
|
headerOrder = Csv.genericHeaderOrder allocationUserTableCsvOptions
|
||||||
|
|
||||||
instance CsvColumnsExplained AllocationUserTableCsv where
|
instance CsvColumnsExplained AllocationUserTableCsv where
|
||||||
csvColumnsExplanations = genericCsvColumnsExplanations allocationUserTableCsvOptions $ mconcat
|
csvColumnsExplanations = genericCsvColumnsExplanations allocationUserTableCsvOptions $ mconcat
|
||||||
|
|||||||
@ -42,7 +42,7 @@ getCAppsFilesR :: TermId -> SchoolId -> CourseShorthand -> Handler TypedContent
|
|||||||
getCAppsFilesR tid ssh csh = do
|
getCAppsFilesR tid ssh csh = do
|
||||||
runDB . existsBy404 $ TermSchoolCourseShort tid ssh csh
|
runDB . existsBy404 $ TermSchoolCourseShort tid ssh csh
|
||||||
MsgRenderer mr <- getMsgRenderer
|
MsgRenderer mr <- getMsgRenderer
|
||||||
|
|
||||||
archiveName <- fmap (flip addExtension (unpack extensionZip) . unpack) . ap getMessageRender . pure $ MsgCourseAllApplicationsArchiveName tid ssh csh
|
archiveName <- fmap (flip addExtension (unpack extensionZip) . unpack) . ap getMessageRender . pure $ MsgCourseAllApplicationsArchiveName tid ssh csh
|
||||||
|
|
||||||
let
|
let
|
||||||
@ -61,12 +61,12 @@ getCAppsFilesR tid ssh csh = do
|
|||||||
hasReadAccessTo $ CApplicationR tid ssh csh cID CAFilesR
|
hasReadAccessTo $ CApplicationR tid ssh csh cID CAFilesR
|
||||||
let
|
let
|
||||||
applicationAllocs = setOf (folded . _1) apps'
|
applicationAllocs = setOf (folded . _1) apps'
|
||||||
|
|
||||||
allocations = applicationAllocs ^.. folded . _Just . _entityVal . $(multifocusG 3) _allocationTerm _allocationSchool _allocationShorthand
|
allocations = applicationAllocs ^.. folded . _Just . _entityVal . $(multifocusG 3) _allocationTerm _allocationSchool _allocationShorthand
|
||||||
|
|
||||||
allEqualOn :: Eq x => Getter _ x -> Bool
|
allEqualOn :: Eq x => Getter _ x -> Bool
|
||||||
allEqualOn l = maybe True (\x -> allOf (folded . l) (== x) allocations) (allocations ^? _head . l)
|
allEqualOn l = maybe True (\x -> allOf (folded . l) (== x) allocations) (allocations ^? _head . l)
|
||||||
|
|
||||||
mkAllocationDir mbAlloc
|
mkAllocationDir mbAlloc
|
||||||
| not $ allEqualOn _1
|
| not $ allEqualOn _1
|
||||||
, Just Allocation{..} <- mbAlloc
|
, Just Allocation{..} <- mbAlloc
|
||||||
@ -92,7 +92,7 @@ getCAppsFilesR tid ssh csh = do
|
|||||||
fileEntitySource = E.selectSource . E.from $ \courseApplicationFile -> do
|
fileEntitySource = E.selectSource . E.from $ \courseApplicationFile -> do
|
||||||
E.where_ $ courseApplicationFile E.^. CourseApplicationFileApplication E.==. E.val appId
|
E.where_ $ courseApplicationFile E.^. CourseApplicationFileApplication E.==. E.val appId
|
||||||
return courseApplicationFile
|
return courseApplicationFile
|
||||||
|
|
||||||
yield $ _FileReference # ( FileReference
|
yield $ _FileReference # ( FileReference
|
||||||
{ fileReferenceModified = courseApplicationTime
|
{ fileReferenceModified = courseApplicationTime
|
||||||
, fileReferenceTitle = mkAppDir ""
|
, fileReferenceTitle = mkAppDir ""
|
||||||
|
|||||||
@ -47,7 +47,7 @@ type CourseApplicationsTableData = DBRow ( Entity CourseApplication
|
|||||||
, Maybe (Entity StudyDegree)
|
, Maybe (Entity StudyDegree)
|
||||||
, Bool -- isParticipant
|
, Bool -- isParticipant
|
||||||
)
|
)
|
||||||
|
|
||||||
courseApplicationsIdent :: Text
|
courseApplicationsIdent :: Text
|
||||||
courseApplicationsIdent = "applications"
|
courseApplicationsIdent = "applications"
|
||||||
|
|
||||||
@ -120,7 +120,7 @@ instance Csv.FromField CourseApplicationsTableVeto where
|
|||||||
(CI.map Text.strip -> t :: CI Text) <- Csv.parseField f
|
(CI.map Text.strip -> t :: CI Text) <- Csv.parseField f
|
||||||
return . CourseApplicationsTableVeto $ elem t
|
return . CourseApplicationsTableVeto $ elem t
|
||||||
[ "veto", "v", "yes", "y", "ja", "j", "wahr", "w", "true", "t", "1" ]
|
[ "veto", "v", "yes", "y", "ja", "j", "wahr", "w", "true", "t", "1" ]
|
||||||
|
|
||||||
data CourseApplicationsTableCsv = CourseApplicationsTableCsv
|
data CourseApplicationsTableCsv = CourseApplicationsTableCsv
|
||||||
{ csvCAAllocation :: Maybe AllocationShorthand
|
{ csvCAAllocation :: Maybe AllocationShorthand
|
||||||
, csvCAApplication :: Maybe CryptoFileNameCourseApplication
|
, csvCAApplication :: Maybe CryptoFileNameCourseApplication
|
||||||
@ -223,7 +223,7 @@ instance Exception CourseApplicationsTableCsvException
|
|||||||
|
|
||||||
embedRenderMessage ''UniWorX ''CourseApplicationsTableCsvException id
|
embedRenderMessage ''UniWorX ''CourseApplicationsTableCsvException id
|
||||||
|
|
||||||
|
|
||||||
data ButtonAcceptApplications = BtnAcceptApplications
|
data ButtonAcceptApplications = BtnAcceptApplications
|
||||||
deriving (Enum, Eq, Ord, Bounded, Read, Show, Generic, Typeable)
|
deriving (Enum, Eq, Ord, Bounded, Read, Show, Generic, Typeable)
|
||||||
instance Universe ButtonAcceptApplications
|
instance Universe ButtonAcceptApplications
|
||||||
@ -277,7 +277,7 @@ postCApplicationsR tid ssh csh = do
|
|||||||
applicationLink appId = liftHandler $ do
|
applicationLink appId = liftHandler $ do
|
||||||
cID <- encrypt appId
|
cID <- encrypt appId
|
||||||
return . SomeRoute $ CApplicationR tid ssh csh cID CAEditR
|
return . SomeRoute $ CApplicationR tid ssh csh cID CAEditR
|
||||||
|
|
||||||
dbtSQLQuery :: CourseApplicationsTableExpr -> E.SqlQuery _
|
dbtSQLQuery :: CourseApplicationsTableExpr -> E.SqlQuery _
|
||||||
dbtSQLQuery = runReaderT $ do
|
dbtSQLQuery = runReaderT $ do
|
||||||
courseApplication <- view queryCourseApplication
|
courseApplication <- view queryCourseApplication
|
||||||
@ -415,13 +415,13 @@ postCApplicationsR tid ssh csh = do
|
|||||||
-> return () -- no addition
|
-> return () -- no addition
|
||||||
DBCsvDiffExisting{..} -> do
|
DBCsvDiffExisting{..} -> do
|
||||||
let appId = dbCsvOld ^. resultCourseApplication . _entityKey
|
let appId = dbCsvOld ^. resultCourseApplication . _entityKey
|
||||||
|
|
||||||
newFeatures <- lift $ lookupStudyFeatures dbCsvNew
|
newFeatures <- lift $ lookupStudyFeatures dbCsvNew
|
||||||
when (newFeatures /= dbCsvOld ^? resultStudyFeatures . _entityKey) $
|
when (newFeatures /= dbCsvOld ^? resultStudyFeatures . _entityKey) $
|
||||||
yield $ CourseApplicationsTableCsvSetFieldData appId newFeatures
|
yield $ CourseApplicationsTableCsvSetFieldData appId newFeatures
|
||||||
|
|
||||||
let mVeto = dbCsvNew ^? _csvCAVeto . _Just . _CourseApplicationsTableVeto
|
let mVeto = dbCsvNew ^? _csvCAVeto . _Just . _CourseApplicationsTableVeto
|
||||||
whenIsJust mVeto $ \veto ->
|
whenIsJust mVeto $ \veto ->
|
||||||
when (veto /= dbCsvOld ^. resultCourseApplication . _entityVal . _courseApplicationRatingVeto) $
|
when (veto /= dbCsvOld ^. resultCourseApplication . _entityVal . _courseApplicationRatingVeto) $
|
||||||
yield $ CourseApplicationsTableCsvSetVetoData appId veto
|
yield $ CourseApplicationsTableCsvSetVetoData appId veto
|
||||||
|
|
||||||
@ -638,7 +638,7 @@ postCApplicationsR tid ssh csh = do
|
|||||||
let title = prependCourseTitle tid ssh csh MsgCourseApplicationsListTitle
|
let title = prependCourseTitle tid ssh csh MsgCourseApplicationsListTitle
|
||||||
registrationOpen = maybe True (now <)
|
registrationOpen = maybe True (now <)
|
||||||
|
|
||||||
|
|
||||||
((acceptRes, acceptWgt'), acceptEnc) <- runFormPost . identifyForm BtnAcceptApplications . renderAForm FormStandard $
|
((acceptRes, acceptWgt'), acceptEnc) <- runFormPost . identifyForm BtnAcceptApplications . renderAForm FormStandard $
|
||||||
(,) <$> apopt (selectField optionsFinite) (fslI MsgAcceptApplicationsMode & setTooltip MsgAcceptApplicationsModeTip) (Just AcceptApplicationsInvite)
|
(,) <$> apopt (selectField optionsFinite) (fslI MsgAcceptApplicationsMode & setTooltip MsgAcceptApplicationsModeTip) (Just AcceptApplicationsInvite)
|
||||||
<*> apopt (selectField optionsFinite) (fslI MsgAcceptApplicationsSecondary & setTooltip MsgAcceptApplicationsSecondaryTip) (Just AcceptApplicationsSecondaryTime)
|
<*> apopt (selectField optionsFinite) (fslI MsgAcceptApplicationsSecondary & setTooltip MsgAcceptApplicationsSecondaryTip) (Just AcceptApplicationsSecondaryTime)
|
||||||
@ -679,7 +679,7 @@ postCApplicationsR tid ssh csh = do
|
|||||||
AcceptApplicationsSecondaryRandom
|
AcceptApplicationsSecondaryRandom
|
||||||
-> comparing $ view ratingL
|
-> comparing $ view ratingL
|
||||||
sortedApplications <- unstableSortBy cmp applications
|
sortedApplications <- unstableSortBy cmp applications
|
||||||
|
|
||||||
let applicants = sortedApplications
|
let applicants = sortedApplications
|
||||||
& nubOn (view $ _1 . _entityKey)
|
& nubOn (view $ _1 . _entityKey)
|
||||||
& maybe id take openCapacity
|
& maybe id take openCapacity
|
||||||
@ -687,7 +687,7 @@ postCApplicationsR tid ssh csh = do
|
|||||||
AcceptApplicationsDirect -> folded . _1 . _entityKey . to Right
|
AcceptApplicationsDirect -> folded . _1 . _entityKey . to Right
|
||||||
AcceptApplicationsInvite -> folded . _1 . _entityVal . _userEmail . to Left
|
AcceptApplicationsInvite -> folded . _1 . _entityVal . _userEmail . to Left
|
||||||
)
|
)
|
||||||
|
|
||||||
mapM_ addMessage' <=< execWriterT $ registerUsers cid applicants
|
mapM_ addMessage' <=< execWriterT $ registerUsers cid applicants
|
||||||
redirect $ CourseR tid ssh csh CUsersR
|
redirect $ CourseR tid ssh csh CUsersR
|
||||||
|
|
||||||
|
|||||||
@ -94,7 +94,7 @@ postCCommR tid ssh csh = do
|
|||||||
E.where_ $ courseParticipant E.^. CourseParticipantCourse E.==. E.val cid
|
E.where_ $ courseParticipant E.^. CourseParticipantCourse E.==. E.val cid
|
||||||
E.&&. courseParticipant E.^. CourseParticipantUser E.==. user E.^. UserId
|
E.&&. courseParticipant E.^. CourseParticipantUser E.==. user E.^. UserId
|
||||||
E.&&. courseParticipant E.^. CourseParticipantState E.==. E.val CourseParticipantActive
|
E.&&. courseParticipant E.^. CourseParticipantState E.==. E.val CourseParticipantActive
|
||||||
return user
|
return user
|
||||||
)
|
)
|
||||||
] ++ tuts ++ exams ++ sheets
|
] ++ tuts ++ exams ++ sheets
|
||||||
, crRecipientAuth = Just $ \uid -> do
|
, crRecipientAuth = Just $ \uid -> do
|
||||||
|
|||||||
@ -92,7 +92,7 @@ courseToForm cEnt@(Entity cid Course{..}) lecs lecInvites alloc = CourseForm
|
|||||||
where selectAppFiles = E.selectSource . E.from $ \courseAppInstructionFile -> do
|
where selectAppFiles = E.selectSource . E.from $ \courseAppInstructionFile -> do
|
||||||
E.where_ $ courseAppInstructionFile E.^. CourseAppInstructionFileCourse E.==. E.val cid
|
E.where_ $ courseAppInstructionFile E.^. CourseAppInstructionFileCourse E.==. E.val cid
|
||||||
return courseAppInstructionFile
|
return courseAppInstructionFile
|
||||||
|
|
||||||
|
|
||||||
allocationCourseToForm :: Entity Course -> Entity AllocationCourse -> AllocationCourseForm
|
allocationCourseToForm :: Entity Course -> Entity AllocationCourse -> AllocationCourseForm
|
||||||
allocationCourseToForm (Entity _ Course{..}) (Entity _ AllocationCourse{..}) = AllocationCourseForm
|
allocationCourseToForm (Entity _ Course{..}) (Entity _ AllocationCourse{..}) = AllocationCourseForm
|
||||||
@ -139,7 +139,7 @@ makeCourseForm miButtonAction template = identifyForm FIDcourse . validateFormDB
|
|||||||
, not $ Set.null existing
|
, not $ Set.null existing
|
||||||
-> FormFailure [mr MsgCourseLecturerAlreadyAdded]
|
-> FormFailure [mr MsgCourseLecturerAlreadyAdded]
|
||||||
| otherwise
|
| otherwise
|
||||||
-> FormSuccess . Map.fromList . zip [maybe 0 succ . fmap fst $ Map.lookupMax oldDat ..] $ Set.toList newDat
|
-> FormSuccess . Map.fromList . zip [maybe 0 (succ . fst) $ Map.lookupMax oldDat ..] $ Set.toList newDat
|
||||||
addView' = $(widgetFile "course/lecturerMassInput/add")
|
addView' = $(widgetFile "course/lecturerMassInput/add")
|
||||||
return (addRes'', addView')
|
return (addRes'', addView')
|
||||||
|
|
||||||
@ -199,10 +199,11 @@ makeCourseForm miButtonAction template = identifyForm FIDcourse . validateFormDB
|
|||||||
(Just cform) | (Just _cid) <- cfCourseId cform -> return (Nothing,Nothing,Nothing,Nothing)
|
(Just cform) | (Just _cid) <- cfCourseId cform -> return (Nothing,Nothing,Nothing,Nothing)
|
||||||
_allIOtherCases -> do
|
_allIOtherCases -> do
|
||||||
mbLastTerm <- liftHandler $ runDB $ selectFirst [TermActive ==. True] [Desc TermName]
|
mbLastTerm <- liftHandler $ runDB $ selectFirst [TermActive ==. True] [Desc TermName]
|
||||||
return ( Just (Just now)
|
return ( Just $ Just now
|
||||||
, (Just . toMidnight . termStart . entityVal) <$> mbLastTerm
|
, Just . toMidnight . termStart . entityVal <$> mbLastTerm
|
||||||
, (Just . beforeMidnight . termEnd . entityVal) <$> mbLastTerm
|
, Just . beforeMidnight . termEnd . entityVal <$> mbLastTerm
|
||||||
, (Just . beforeMidnight . termEnd . entityVal) <$> mbLastTerm )
|
, Just . beforeMidnight . termEnd . entityVal <$> mbLastTerm
|
||||||
|
)
|
||||||
|
|
||||||
let
|
let
|
||||||
allocationForm :: AForm Handler (Maybe AllocationCourseForm)
|
allocationForm :: AForm Handler (Maybe AllocationCourseForm)
|
||||||
@ -214,7 +215,7 @@ makeCourseForm miButtonAction template = identifyForm FIDcourse . validateFormDB
|
|||||||
E.exists . E.from $ \allocationCourse ->
|
E.exists . E.from $ \allocationCourse ->
|
||||||
E.where_ $ allocationCourse E.^. AllocationCourseCourse E.==. E.val cid
|
E.where_ $ allocationCourse E.^. AllocationCourseCourse E.==. E.val cid
|
||||||
E.&&. allocationCourse E.^. AllocationCourseAllocation E.==. allocation E.^. AllocationId
|
E.&&. allocationCourse E.^. AllocationCourseAllocation E.==. allocation E.^. AllocationId
|
||||||
|
|
||||||
E.where_ $ term E.^. TermActive
|
E.where_ $ term E.^. TermActive
|
||||||
E.||. alreadyParticipates
|
E.||. alreadyParticipates
|
||||||
E.||. allocation E.^. AllocationSchool `E.in_` E.valList adminSchools
|
E.||. allocation E.^. AllocationSchool `E.in_` E.valList adminSchools
|
||||||
@ -243,8 +244,8 @@ makeCourseForm miButtonAction template = identifyForm FIDcourse . validateFormDB
|
|||||||
|
|
||||||
let
|
let
|
||||||
userAdmin = not $ null adminSchools
|
userAdmin = not $ null adminSchools
|
||||||
mayChange = fromMaybe True $ (|| userAdmin) <$> currentAllocationAvailable
|
mayChange = Just False /= fmap (|| userAdmin) currentAllocationAvailable
|
||||||
|
|
||||||
allocationForm' =
|
allocationForm' =
|
||||||
let ainp :: Field Handler a -> FieldSettings UniWorX -> Maybe a -> AForm Handler a
|
let ainp :: Field Handler a -> FieldSettings UniWorX -> Maybe a -> AForm Handler a
|
||||||
ainp
|
ainp
|
||||||
@ -265,8 +266,8 @@ makeCourseForm miButtonAction template = identifyForm FIDcourse . validateFormDB
|
|||||||
multipleTermsMsg <- messageI Warning MsgCourseSemesterMultipleTip
|
multipleTermsMsg <- messageI Warning MsgCourseSemesterMultipleTip
|
||||||
|
|
||||||
(result, widget) <- flip (renderAForm FormStandard) html $ CourseForm
|
(result, widget) <- flip (renderAForm FormStandard) html $ CourseForm
|
||||||
<$> pure (cfCourseId =<< template)
|
(cfCourseId =<< template)
|
||||||
<*> areq (textField & cfStrip & cfCI) (fslI MsgCourseName) (cfName <$> template)
|
<$> areq (textField & cfStrip & cfCI) (fslI MsgCourseName) (cfName <$> template)
|
||||||
<*> areq (textField & cfStrip & cfCI) (fslpI MsgCourseShorthand "ProMo, LinAlg1, AlgoDat, Ana2, EiP, …"
|
<*> areq (textField & cfStrip & cfCI) (fslpI MsgCourseShorthand "ProMo, LinAlg1, AlgoDat, Ana2, EiP, …"
|
||||||
-- & addAttr "disabled" "disabled"
|
-- & addAttr "disabled" "disabled"
|
||||||
& setTooltip MsgCourseShorthandUnique) (cfShort <$> template)
|
& setTooltip MsgCourseShorthandUnique) (cfShort <$> template)
|
||||||
@ -333,7 +334,7 @@ validateCourse = do
|
|||||||
guardValidation MsgCourseRegistrationEndMustBeAfterStart
|
guardValidation MsgCourseRegistrationEndMustBeAfterStart
|
||||||
$ NTop cfRegFrom <= NTop cfRegTo
|
$ NTop cfRegFrom <= NTop cfRegTo
|
||||||
guardValidation MsgCourseDeregistrationEndMustBeAfterStart
|
guardValidation MsgCourseDeregistrationEndMustBeAfterStart
|
||||||
$ fromMaybe True $ (<=) <$> cfRegFrom <*> cfDeRegUntil
|
$ Just False /= ((<=) <$> cfRegFrom <*> cfDeRegUntil)
|
||||||
unless userAdmin $
|
unless userAdmin $
|
||||||
guardValidation MsgCourseUserMustBeLecturer
|
guardValidation MsgCourseUserMustBeLecturer
|
||||||
$ anyOf (traverse . _Right . _1) (== uid) cfLecturers
|
$ anyOf (traverse . _Right . _1) (== uid) cfLecturers
|
||||||
@ -538,7 +539,7 @@ courseEditHandler miButtonAction mbCourseForm = do
|
|||||||
insert_ $ CourseEdit aid now cid
|
insert_ $ CourseEdit aid now cid
|
||||||
|
|
||||||
let mkFilter CourseAppInstructionFileResidual{..} = [ CourseAppInstructionFileCourse ==. courseAppInstructionFileResidualCourse ]
|
let mkFilter CourseAppInstructionFileResidual{..} = [ CourseAppInstructionFileCourse ==. courseAppInstructionFileResidualCourse ]
|
||||||
in void . replaceFileReferences mkFilter (CourseAppInstructionFileResidual cid) . traverse_ id $ cfAppInstructionFiles res
|
in void . replaceFileReferences mkFilter (CourseAppInstructionFileResidual cid) . sequence_ $ cfAppInstructionFiles res
|
||||||
|
|
||||||
upsertAllocationCourse cid $ cfAllocation res
|
upsertAllocationCourse cid $ cfAllocation res
|
||||||
|
|
||||||
@ -556,7 +557,7 @@ courseEditHandler miButtonAction mbCourseForm = do
|
|||||||
upsertAllocationCourse :: (MonadThrow m, MonadHandler m, HandlerSite m ~ UniWorX) => CourseId -> Maybe AllocationCourseForm -> ReaderT SqlBackend m ()
|
upsertAllocationCourse :: (MonadThrow m, MonadHandler m, HandlerSite m ~ UniWorX) => CourseId -> Maybe AllocationCourseForm -> ReaderT SqlBackend m ()
|
||||||
upsertAllocationCourse cid cfAllocation = do
|
upsertAllocationCourse cid cfAllocation = do
|
||||||
now <- liftIO getCurrentTime
|
now <- liftIO getCurrentTime
|
||||||
Course{..} <- getJust cid
|
Course{} <- getJust cid
|
||||||
prevAllocationCourse <- getBy $ UniqueAllocationCourse cid
|
prevAllocationCourse <- getBy $ UniqueAllocationCourse cid
|
||||||
prevAllocation <- fmap join . traverse get $ allocationCourseAllocation . entityVal <$> prevAllocationCourse
|
prevAllocation <- fmap join . traverse get $ allocationCourseAllocation . entityVal <$> prevAllocationCourse
|
||||||
userAdmin <- fromMaybe False <$> for prevAllocation (\Allocation{..} -> hasWriteAccessTo $ SchoolR allocationSchool SchoolEditR)
|
userAdmin <- fromMaybe False <$> for prevAllocation (\Allocation{..} -> hasWriteAccessTo $ SchoolR allocationSchool SchoolEditR)
|
||||||
|
|||||||
@ -8,13 +8,13 @@ import Handler.Utils.Occurrences
|
|||||||
import Handler.Utils.Delete
|
import Handler.Utils.Delete
|
||||||
|
|
||||||
import qualified Data.Set as Set
|
import qualified Data.Set as Set
|
||||||
|
|
||||||
|
|
||||||
getCEvDeleteR, postCEvDeleteR :: TermId -> SchoolId -> CourseShorthand -> CryptoUUIDCourseEvent -> Handler Html
|
getCEvDeleteR, postCEvDeleteR :: TermId -> SchoolId -> CourseShorthand -> CryptoUUIDCourseEvent -> Handler Html
|
||||||
getCEvDeleteR = postCEvDeleteR
|
getCEvDeleteR = postCEvDeleteR
|
||||||
postCEvDeleteR tid ssh csh cID = do
|
postCEvDeleteR tid ssh csh cID = do
|
||||||
nId <- decrypt cID
|
nId <- decrypt cID
|
||||||
|
|
||||||
let
|
let
|
||||||
drRecords :: Set (Key CourseEvent)
|
drRecords :: Set (Key CourseEvent)
|
||||||
drRecords = Set.singleton nId
|
drRecords = Set.singleton nId
|
||||||
@ -31,23 +31,23 @@ postCEvDeleteR tid ssh csh cID = do
|
|||||||
:
|
:
|
||||||
^{occurrencesWidget courseEventTime}
|
^{occurrencesWidget courseEventTime}
|
||||||
|]
|
|]
|
||||||
|
|
||||||
drRecordConfirmString :: Entity CourseEvent -> DB Text
|
drRecordConfirmString :: Entity CourseEvent -> DB Text
|
||||||
drRecordConfirmString _ = return ""
|
drRecordConfirmString _ = return ""
|
||||||
|
|
||||||
drCaption, drSuccessMessage :: SomeMessage UniWorX
|
drCaption, drSuccessMessage :: SomeMessage UniWorX
|
||||||
drCaption = SomeMessage MsgCourseEventDeleteQuestion
|
drCaption = SomeMessage MsgCourseEventDeleteQuestion
|
||||||
drSuccessMessage = SomeMessage MsgCourseEventDeleted
|
drSuccessMessage = SomeMessage MsgCourseEventDeleted
|
||||||
|
|
||||||
drAbort, drSuccess :: SomeRoute UniWorX
|
drAbort, drSuccess :: SomeRoute UniWorX
|
||||||
drAbort = SomeRoute $ CourseR tid ssh csh CShowR :#: [st|event-#{toPathPiece cID}|]
|
drAbort = SomeRoute $ CourseR tid ssh csh CShowR :#: [st|event-#{toPathPiece cID}|]
|
||||||
drSuccess = SomeRoute $ CourseR tid ssh csh CShowR
|
drSuccess = SomeRoute $ CourseR tid ssh csh CShowR
|
||||||
|
|
||||||
drFormMessage :: [Entity CourseEvent] -> DB (Maybe Message)
|
drFormMessage :: [Entity CourseEvent] -> DB (Maybe Message)
|
||||||
drFormMessage _ = return Nothing
|
drFormMessage _ = return Nothing
|
||||||
|
|
||||||
drDelete :: forall a. CourseEventId -> JobDB a -> JobDB a
|
drDelete :: forall a. CourseEventId -> JobDB a -> JobDB a
|
||||||
drDelete _ = id
|
drDelete _ = id
|
||||||
|
|
||||||
deleteR DeleteRoute{..}
|
deleteR DeleteRoute{..}
|
||||||
|
|
||||||
|
|||||||
@ -4,7 +4,7 @@ module Handler.Course.Events.Edit
|
|||||||
|
|
||||||
import Import
|
import Import
|
||||||
import Handler.Utils
|
import Handler.Utils
|
||||||
|
|
||||||
import Handler.Course.Events.Form
|
import Handler.Course.Events.Form
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -31,7 +31,7 @@ courseEventForm template = identifyForm FIDCourseEvent . renderWForm FormStandar
|
|||||||
)
|
)
|
||||||
let courseEventTypes = optionsPairs [ (courseEventType, courseEventType) | Entity _ CourseEvent{..} <- existingEvents ]
|
let courseEventTypes = optionsPairs [ (courseEventType, courseEventType) | Entity _ CourseEvent{..} <- existingEvents ]
|
||||||
courseEventRooms = optionsPairs [ (courseEventRoom, courseEventRoom) | Entity _ CourseEvent{..} <- existingEvents ]
|
courseEventRooms = optionsPairs [ (courseEventRoom, courseEventRoom) | Entity _ CourseEvent{..} <- existingEvents ]
|
||||||
|
|
||||||
cefType' <- wreq (textField & cfStrip & cfCI & addDatalist courseEventTypes) (fslI MsgCourseEventType & addPlaceholder (mr MsgCourseEventTypePlaceholder)) (cefType <$> template)
|
cefType' <- wreq (textField & cfStrip & cfCI & addDatalist courseEventTypes) (fslI MsgCourseEventType & addPlaceholder (mr MsgCourseEventTypePlaceholder)) (cefType <$> template)
|
||||||
cefRoom' <- wreq (textField & cfStrip & addDatalist courseEventRooms) (fslI MsgCourseEventRoom) (cefRoom <$> template)
|
cefRoom' <- wreq (textField & cfStrip & addDatalist courseEventRooms) (fslI MsgCourseEventRoom) (cefRoom <$> template)
|
||||||
cefTime' <- aFormToWForm $ occurrencesAForm ("time" :: Text) (cefTime <$> template)
|
cefTime' <- aFormToWForm $ occurrencesAForm ("time" :: Text) (cefTime <$> template)
|
||||||
|
|||||||
@ -4,7 +4,7 @@ module Handler.Course.Events.New
|
|||||||
|
|
||||||
import Import
|
import Import
|
||||||
import Handler.Utils
|
import Handler.Utils
|
||||||
|
|
||||||
import Handler.Course.Events.Form
|
import Handler.Course.Events.Form
|
||||||
|
|
||||||
getCEventsNewR, postCEventsNewR :: TermId -> SchoolId -> CourseShorthand -> Handler Html
|
getCEventsNewR, postCEventsNewR :: TermId -> SchoolId -> CourseShorthand -> Handler Html
|
||||||
|
|||||||
@ -12,7 +12,7 @@ getCNDeleteR, postCNDeleteR :: TermId -> SchoolId -> CourseShorthand -> CryptoUU
|
|||||||
getCNDeleteR = postCNDeleteR
|
getCNDeleteR = postCNDeleteR
|
||||||
postCNDeleteR tid ssh csh cID = do
|
postCNDeleteR tid ssh csh cID = do
|
||||||
nId <- decrypt cID
|
nId <- decrypt cID
|
||||||
|
|
||||||
let
|
let
|
||||||
drRecords :: Set (Key CourseNews)
|
drRecords :: Set (Key CourseNews)
|
||||||
drRecords = Set.singleton nId
|
drRecords = Set.singleton nId
|
||||||
@ -26,22 +26,22 @@ postCNDeleteR tid ssh csh cID = do
|
|||||||
[ toWidget <$> courseNewsTitle
|
[ toWidget <$> courseNewsTitle
|
||||||
, toWidget <$> courseNewsSummary
|
, toWidget <$> courseNewsSummary
|
||||||
]
|
]
|
||||||
|
|
||||||
drRecordConfirmString :: Entity CourseNews -> DB Text
|
drRecordConfirmString :: Entity CourseNews -> DB Text
|
||||||
drRecordConfirmString _ = return ""
|
drRecordConfirmString _ = return ""
|
||||||
|
|
||||||
drCaption, drSuccessMessage :: SomeMessage UniWorX
|
drCaption, drSuccessMessage :: SomeMessage UniWorX
|
||||||
drCaption = SomeMessage MsgCourseNewsDeleteQuestion
|
drCaption = SomeMessage MsgCourseNewsDeleteQuestion
|
||||||
drSuccessMessage = SomeMessage MsgCourseNewsDeleted
|
drSuccessMessage = SomeMessage MsgCourseNewsDeleted
|
||||||
|
|
||||||
drAbort, drSuccess :: SomeRoute UniWorX
|
drAbort, drSuccess :: SomeRoute UniWorX
|
||||||
drAbort = SomeRoute $ CourseR tid ssh csh CShowR :#: [st|news-#{toPathPiece cID}|]
|
drAbort = SomeRoute $ CourseR tid ssh csh CShowR :#: [st|news-#{toPathPiece cID}|]
|
||||||
drSuccess = SomeRoute $ CourseR tid ssh csh CShowR
|
drSuccess = SomeRoute $ CourseR tid ssh csh CShowR
|
||||||
|
|
||||||
drFormMessage :: [Entity CourseNews] -> DB (Maybe Message)
|
drFormMessage :: [Entity CourseNews] -> DB (Maybe Message)
|
||||||
drFormMessage _ = return Nothing
|
drFormMessage _ = return Nothing
|
||||||
|
|
||||||
drDelete :: forall a. CourseNewsId -> JobDB a -> JobDB a
|
drDelete :: forall a. CourseNewsId -> JobDB a -> JobDB a
|
||||||
drDelete _ = id
|
drDelete _ = id
|
||||||
|
|
||||||
deleteR DeleteRoute{..}
|
deleteR DeleteRoute{..}
|
||||||
|
|||||||
@ -25,7 +25,7 @@ getCNArchiveR tid ssh csh cID = do
|
|||||||
|
|
||||||
serveSomeFiles archiveName getFilesQuery
|
serveSomeFiles archiveName getFilesQuery
|
||||||
|
|
||||||
|
|
||||||
getCNFileR :: TermId -> SchoolId -> CourseShorthand -> CryptoUUIDCourseNews -> FilePath -> Handler TypedContent
|
getCNFileR :: TermId -> SchoolId -> CourseShorthand -> CryptoUUIDCourseNews -> FilePath -> Handler TypedContent
|
||||||
getCNFileR _ _ _ cID title = do
|
getCNFileR _ _ _ cID title = do
|
||||||
nId <- decrypt cID
|
nId <- decrypt cID
|
||||||
|
|||||||
@ -33,8 +33,8 @@ postCNEditR tid ssh csh cID = do
|
|||||||
, courseNewsSummary = cnfSummary
|
, courseNewsSummary = cnfSummary
|
||||||
, courseNewsLastEdit = now
|
, courseNewsLastEdit = now
|
||||||
}
|
}
|
||||||
let mkFilter CourseNewsFileResidual{..} = [ CourseNewsFileNews ==. nId ]
|
let mkFilter CourseNewsFileResidual{} = [ CourseNewsFileNews ==. nId ]
|
||||||
in void . replaceFileReferences mkFilter (CourseNewsFileResidual nId) $ traverse_ id cnfFiles
|
in void . replaceFileReferences mkFilter (CourseNewsFileResidual nId) $ sequence_ cnfFiles
|
||||||
addMessageI Success MsgCourseNewsEdited
|
addMessageI Success MsgCourseNewsEdited
|
||||||
redirect $ CourseR tid ssh csh CShowR :#: [st|news-#{toPathPiece cID}|]
|
redirect $ CourseR tid ssh csh CShowR :#: [st|news-#{toPathPiece cID}|]
|
||||||
|
|
||||||
|
|||||||
@ -16,7 +16,7 @@ data CourseNewsForm = CourseNewsForm
|
|||||||
, cnfContent :: Html
|
, cnfContent :: Html
|
||||||
, cnfParticipantsOnly :: Bool
|
, cnfParticipantsOnly :: Bool
|
||||||
, cnfVisibleFrom :: Maybe UTCTime
|
, cnfVisibleFrom :: Maybe UTCTime
|
||||||
, cnfFiles :: Maybe FileUploads
|
, cnfFiles :: Maybe FileUploads
|
||||||
}
|
}
|
||||||
|
|
||||||
courseNewsForm :: Maybe CourseNewsForm -> Form CourseNewsForm
|
courseNewsForm :: Maybe CourseNewsForm -> Form CourseNewsForm
|
||||||
|
|||||||
@ -92,11 +92,11 @@ participantInvitationConfig = InvitationConfig{..}
|
|||||||
itAuthority <- HashSet.singleton . Right <$> liftHandler requireAuthId
|
itAuthority <- HashSet.singleton . Right <$> liftHandler requireAuthId
|
||||||
return $ InvitationTokenConfig itAuthority Nothing Nothing Nothing
|
return $ InvitationTokenConfig itAuthority Nothing Nothing Nothing
|
||||||
invitationRestriction _ _ = return Authorized
|
invitationRestriction _ _ = return Authorized
|
||||||
invitationForm (Entity _ Course{..}) _ uid = hoistAForm lift . wFormToAForm $ do
|
invitationForm _ _ uid = hoistAForm lift . wFormToAForm $ do
|
||||||
now <- liftIO getCurrentTime
|
now <- liftIO getCurrentTime
|
||||||
studyFeatures <- wreq (studyFeaturesFieldFor Nothing False [] $ Just uid)
|
studyFeatures <- wreq (studyFeaturesFieldFor Nothing False [] $ Just uid)
|
||||||
(fslI MsgCourseStudyFeature & setTooltip MsgCourseStudyFeatureTip) Nothing
|
(fslI MsgCourseStudyFeature & setTooltip MsgCourseStudyFeatureTip) Nothing
|
||||||
return . fmap (, ()) $ JunctionParticipant <$> pure now <*> studyFeatures <*> pure Nothing <*> pure CourseParticipantActive
|
return . fmap (, ()) $ JunctionParticipant now <$> studyFeatures <*> pure Nothing <*> pure CourseParticipantActive
|
||||||
invitationInsertHook _ _ (_, InvTokenDataParticipant{..}) CourseParticipant{..} _ act = do
|
invitationInsertHook _ _ (_, InvTokenDataParticipant{..}) CourseParticipant{..} _ act = do
|
||||||
deleteBy $ UniqueParticipant courseParticipantUser courseParticipantCourse -- there are no foreign key references to @{CourseParticipant}; therefor we can delete and recreate to simulate upsert
|
deleteBy $ UniqueParticipant courseParticipantUser courseParticipantCourse -- there are no foreign key references to @{CourseParticipant}; therefor we can delete and recreate to simulate upsert
|
||||||
res <- act -- insertUnique
|
res <- act -- insertUnique
|
||||||
@ -138,7 +138,7 @@ postCAddUserR tid ssh csh = do
|
|||||||
|
|
||||||
formResultModal usersToEnlist (CourseR tid ssh csh CUsersR) $
|
formResultModal usersToEnlist (CourseR tid ssh csh CUsersR) $
|
||||||
hoist runDBJobs . registerUsers' cid
|
hoist runDBJobs . registerUsers' cid
|
||||||
|
|
||||||
|
|
||||||
let heading = prependCourseTitle tid ssh csh MsgCourseParticipantsRegisterHeading
|
let heading = prependCourseTitle tid ssh csh MsgCourseParticipantsRegisterHeading
|
||||||
|
|
||||||
@ -169,7 +169,7 @@ addParticipantsResultMessages :: (MonadHandler m, HandlerSite m ~ UniWorX)
|
|||||||
=> AddParticipantsResult
|
=> AddParticipantsResult
|
||||||
-> ReaderT (YesodPersistBackend UniWorX) m [Message]
|
-> ReaderT (YesodPersistBackend UniWorX) m [Message]
|
||||||
addParticipantsResultMessages AddParticipantsResult{..} = execWriterT $ do
|
addParticipantsResultMessages AddParticipantsResult{..} = execWriterT $ do
|
||||||
(aurAlreadyRegistered', aurNoUniquePrimaryField') <-
|
(aurAlreadyRegistered', aurNoUniquePrimaryField') <-
|
||||||
(,) <$> fmap sort (lift . mapM (fmap userEmail . getJust) $ Set.toList aurAlreadyRegistered)
|
(,) <$> fmap sort (lift . mapM (fmap userEmail . getJust) $ Set.toList aurAlreadyRegistered)
|
||||||
<*> fmap sort (lift . mapM (fmap userEmail . getJust) $ Set.toList aurNoUniquePrimaryField)
|
<*> fmap sort (lift . mapM (fmap userEmail . getJust) $ Set.toList aurNoUniquePrimaryField)
|
||||||
|
|
||||||
|
|||||||
@ -69,7 +69,7 @@ courseRegisterForm (Entity cid Course{..}) = liftHandler $ do
|
|||||||
isRegistered = btn `elem` [BtnCourseRetractApplication, BtnCourseDeregister]
|
isRegistered = btn `elem` [BtnCourseRetractApplication, BtnCourseDeregister]
|
||||||
return . (, btn) . wFormToAForm $ do
|
return . (, btn) . wFormToAForm $ do
|
||||||
MsgRenderer mr <- getMsgRenderer
|
MsgRenderer mr <- getMsgRenderer
|
||||||
|
|
||||||
secretRes <- if
|
secretRes <- if
|
||||||
| Just secret <- courseRegisterSecret
|
| Just secret <- courseRegisterSecret
|
||||||
, not isRegistered
|
, not isRegistered
|
||||||
@ -118,7 +118,7 @@ courseRegisterForm (Entity cid Course{..}) = liftHandler $ do
|
|||||||
let appFilesInfo = (,) <$> hasFiles <*> appCID
|
let appFilesInfo = (,) <$> hasFiles <*> appCID
|
||||||
filesMsg = bool MsgCourseRegistrationFiles MsgCourseApplicationFiles courseApplicationsRequired
|
filesMsg = bool MsgCourseRegistrationFiles MsgCourseApplicationFiles courseApplicationsRequired
|
||||||
|
|
||||||
when (isn't _NoUpload courseApplicationsFiles || fromMaybe False hasFiles) $
|
when (isn't _NoUpload courseApplicationsFiles || Just True == hasFiles) $
|
||||||
let filesLinkField = Field{..}
|
let filesLinkField = Field{..}
|
||||||
where
|
where
|
||||||
fieldParse _ _ = return $ Right Nothing
|
fieldParse _ _ = return $ Right Nothing
|
||||||
@ -136,7 +136,7 @@ courseRegisterForm (Entity cid Course{..}) = liftHandler $ do
|
|||||||
|]
|
|]
|
||||||
in void $ wforced filesLinkField (fslI filesMsg) Nothing
|
in void $ wforced filesLinkField (fslI filesMsg) Nothing
|
||||||
|
|
||||||
when (fromMaybe False hasFiles && isn't _NoUpload courseApplicationsFiles) $
|
when (Just True == hasFiles && isn't _NoUpload courseApplicationsFiles) $
|
||||||
wformMessage <=< messageIconI Info IconFileUpload $ bool MsgCourseRegistrationFilesNeedReupload MsgCourseApplicationFilesNeedReupload courseApplicationsRequired
|
wformMessage <=< messageIconI Info IconFileUpload $ bool MsgCourseRegistrationFilesNeedReupload MsgCourseApplicationFilesNeedReupload courseApplicationsRequired
|
||||||
|
|
||||||
appFilesRes <- let mkFs | courseApplicationsRequired = bool MsgCourseApplicationFile MsgCourseApplicationArchive
|
appFilesRes <- let mkFs | courseApplicationsRequired = bool MsgCourseApplicationFile MsgCourseApplicationArchive
|
||||||
@ -171,7 +171,7 @@ courseRegisterForm (Entity cid Course{..}) = liftHandler $ do
|
|||||||
<*> appTextRes
|
<*> appTextRes
|
||||||
<*> appFilesRes
|
<*> appFilesRes
|
||||||
|
|
||||||
|
|
||||||
-- | Workaround for klicking register button without being logged in.
|
-- | Workaround for klicking register button without being logged in.
|
||||||
-- After log in, the user sees a "get request not supported" error.
|
-- After log in, the user sees a "get request not supported" error.
|
||||||
getCRegisterR :: TermId -> SchoolId -> CourseShorthand -> Handler Html
|
getCRegisterR :: TermId -> SchoolId -> CourseShorthand -> Handler Html
|
||||||
@ -212,8 +212,8 @@ postCRegisterR tid ssh csh = do
|
|||||||
|
|
||||||
return $ Just prevId
|
return $ Just prevId
|
||||||
|
|
||||||
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_ (insert_ . review _FileReference . (, CourseApplicationFileResidual appId))
|
runConduit $ transPipe liftHandler fSource .| C.mapM_ (insert_ . review _FileReference . (, CourseApplicationFileResidual appId))
|
||||||
return appRes
|
return appRes
|
||||||
@ -288,7 +288,7 @@ deregisterParticipant :: UserId -> CourseId -> DB ()
|
|||||||
deregisterParticipant uid cid = do
|
deregisterParticipant uid cid = do
|
||||||
deleteApplications uid cid
|
deleteApplications uid cid
|
||||||
part <- fmap (assertM . has $ _entityVal . _courseParticipantState . _CourseParticipantActive) . getBy $ UniqueParticipant uid cid
|
part <- fmap (assertM . has $ _entityVal . _courseParticipantState . _CourseParticipantActive) . getBy $ UniqueParticipant uid cid
|
||||||
forM_ part $ \(Entity partId CourseParticipant{..}) -> do
|
forM_ part $ \(Entity partId CourseParticipant{}) -> do
|
||||||
update partId [CourseParticipantState =. CourseParticipantInactive False]
|
update partId [CourseParticipantState =. CourseParticipantInactive False]
|
||||||
audit $ TransactionCourseParticipantDeleted cid uid
|
audit $ TransactionCourseParticipantDeleted cid uid
|
||||||
|
|
||||||
@ -300,7 +300,7 @@ deregisterParticipant uid cid = do
|
|||||||
forM_ examRegistrations $ \(Entity erId ExamRegistration{..}) -> do
|
forM_ examRegistrations $ \(Entity erId ExamRegistration{..}) -> do
|
||||||
delete erId
|
delete erId
|
||||||
audit $ TransactionExamDeregister examRegistrationExam uid
|
audit $ TransactionExamDeregister examRegistrationExam uid
|
||||||
|
|
||||||
E.delete . E.from $ \tutorialParticipant -> do
|
E.delete . E.from $ \tutorialParticipant -> do
|
||||||
let tutorialCourse = E.subSelectForeign tutorialParticipant TutorialParticipantTutorial (E.^. TutorialCourse)
|
let tutorialCourse = E.subSelectForeign tutorialParticipant TutorialParticipantTutorial (E.^. TutorialCourse)
|
||||||
|
|
||||||
|
|||||||
@ -109,12 +109,11 @@ getCShowR tid ssh csh = do
|
|||||||
return (cid,course,courseVisible,schoolName,participants,registration,lecturers,assistants,correctors,tutors,mAllocation,hasApplicationTemplate,mApplication,news,events,submissionGroup,hasAllocationRegistrationOpen)
|
return (cid,course,courseVisible,schoolName,participants,registration,lecturers,assistants,correctors,tutors,mAllocation,hasApplicationTemplate,mApplication,news,events,submissionGroup,hasAllocationRegistrationOpen)
|
||||||
|
|
||||||
let mDereg' = maybe id min (allocationOverrideDeregister =<< mAllocation) <$> courseDeregisterUntil course
|
let mDereg' = maybe id min (allocationOverrideDeregister =<< mAllocation) <$> courseDeregisterUntil course
|
||||||
mDereg <- traverse (formatTime SelFormatDateTime) mDereg'
|
mDereg <- traverse (formatTime SelFormatDateTime) mDereg'
|
||||||
|
|
||||||
cID <- encrypt cid :: Handler CryptoUUIDCourse
|
cID <- encrypt cid :: Handler CryptoUUIDCourse
|
||||||
mAllocation' <- for mAllocation $ \alloc@Allocation{..} -> (,)
|
mAllocation' <- for mAllocation $ \alloc@Allocation{..} -> (alloc, )
|
||||||
<$> pure alloc
|
<$> toTextUrl (AllocationR allocationTerm allocationSchool allocationShorthand AShowR :#: cID)
|
||||||
<*> toTextUrl (AllocationR allocationTerm allocationSchool allocationShorthand AShowR :#: cID)
|
|
||||||
regForm <- if
|
regForm <- if
|
||||||
| is _Just mbAid -> do
|
| is _Just mbAid -> do
|
||||||
(courseRegisterForm', regButton) <- courseRegisterForm (Entity cid course)
|
(courseRegisterForm', regButton) <- courseRegisterForm (Entity cid course)
|
||||||
@ -127,9 +126,9 @@ getCShowR tid ssh csh = do
|
|||||||
| otherwise
|
| otherwise
|
||||||
-> return . modal $(widgetFile "course/login-to-register") . Left . SomeRoute $ AuthR LoginR
|
-> return . modal $(widgetFile "course/login-to-register") . Left . SomeRoute $ AuthR LoginR
|
||||||
registrationOpen <- hasWriteAccessTo $ CourseR tid ssh csh CRegisterR
|
registrationOpen <- hasWriteAccessTo $ CourseR tid ssh csh CRegisterR
|
||||||
|
|
||||||
MsgRenderer mr <- getMsgRenderer
|
MsgRenderer mr <- getMsgRenderer
|
||||||
|
|
||||||
let
|
let
|
||||||
tutorialDBTable = DBTable{..}
|
tutorialDBTable = DBTable{..}
|
||||||
where
|
where
|
||||||
|
|||||||
@ -60,7 +60,7 @@ postCUserR tid ssh csh uCId = do
|
|||||||
registered <- exists [ CourseParticipantCourse ==. cid, CourseParticipantUser ==. uid, CourseParticipantState ==. CourseParticipantActive ]
|
registered <- exists [ CourseParticipantCourse ==. cid, CourseParticipantUser ==. uid, CourseParticipantState ==. CourseParticipantActive ]
|
||||||
|
|
||||||
return (course, Entity uid user, registered)
|
return (course, Entity uid user, registered)
|
||||||
|
|
||||||
sections <- mapM (runMaybeT . ($ user) . ($ course))
|
sections <- mapM (runMaybeT . ($ user) . ($ course))
|
||||||
[ courseUserProfileSection
|
[ courseUserProfileSection
|
||||||
, courseUserNoteSection
|
, courseUserNoteSection
|
||||||
@ -115,7 +115,7 @@ courseUserProfileSection (Entity cid Course{..}) (Entity uid User{ userShowSex =
|
|||||||
, formSubmit = FormAutoSubmit
|
, formSubmit = FormAutoSubmit
|
||||||
, formAnchor = Just registrationFieldFrag
|
, formAnchor = Just registrationFieldFrag
|
||||||
}
|
}
|
||||||
for_ mRegistration $ \(Entity pId CourseParticipant{..}) ->
|
for_ mRegistration $ \(Entity pId CourseParticipant{}) ->
|
||||||
formResult regFieldRes $ \courseParticipantField' -> do
|
formResult regFieldRes $ \courseParticipantField' -> do
|
||||||
lift . runDB $ do
|
lift . runDB $ do
|
||||||
update pId [ CourseParticipantField =. courseParticipantField' ]
|
update pId [ CourseParticipantField =. courseParticipantField' ]
|
||||||
@ -202,11 +202,11 @@ courseUserProfileSection (Entity cid Course{..}) (Entity uid User{ userShowSex =
|
|||||||
|
|
||||||
return $(widgetFile "course/user/profile")
|
return $(widgetFile "course/user/profile")
|
||||||
|
|
||||||
|
|
||||||
courseUserNoteSection :: Entity Course -> Entity User -> MaybeT Handler Widget
|
courseUserNoteSection :: Entity Course -> Entity User -> MaybeT Handler Widget
|
||||||
courseUserNoteSection (Entity cid Course{..}) (Entity uid _) = do
|
courseUserNoteSection (Entity cid Course{..}) (Entity uid _) = do
|
||||||
guardM . hasWriteAccessTo $ CourseR courseTerm courseSchool courseShorthand CUsersR
|
guardM . hasWriteAccessTo $ CourseR courseTerm courseSchool courseShorthand CUsersR
|
||||||
|
|
||||||
currentRoute <- MaybeT getCurrentRoute
|
currentRoute <- MaybeT getCurrentRoute
|
||||||
|
|
||||||
(thisUniqueNote, noteText, noteEdits) <- lift . runDB $ do
|
(thisUniqueNote, noteText, noteEdits) <- lift . runDB $ do
|
||||||
@ -306,7 +306,7 @@ courseUserExamsSection (Entity cid Course{..}) (Entity uid _) = do
|
|||||||
guardM . hasWriteAccessTo $ CourseR courseTerm courseSchool courseShorthand CExamNewR
|
guardM . hasWriteAccessTo $ CourseR courseTerm courseSchool courseShorthand CExamNewR
|
||||||
|
|
||||||
uCID <- encrypt uid
|
uCID <- encrypt uid
|
||||||
|
|
||||||
let
|
let
|
||||||
examDBTable = DBTable{..}
|
examDBTable = DBTable{..}
|
||||||
where
|
where
|
||||||
|
|||||||
@ -139,7 +139,7 @@ _userSheets = _dbrOutput . _8
|
|||||||
|
|
||||||
colUserComment :: IsDBTable m c => TermId -> SchoolId -> CourseShorthand -> Colonnade Sortable UserTableData (DBCell m c)
|
colUserComment :: IsDBTable m c => TermId -> SchoolId -> CourseShorthand -> Colonnade Sortable UserTableData (DBCell m c)
|
||||||
colUserComment tid ssh csh =
|
colUserComment tid ssh csh =
|
||||||
sortable (Just "note") (i18nCell MsgCourseUserNote) $ views (_dbrOutput . $(multifocusG 2) (_1 . _entityKey) _3) $ \(uid, mbNoteKey) ->
|
sortable (Just "note") (i18nCell MsgCourseUserNote) $ views (_dbrOutput . $(multifocusG 2) (_1 . _entityKey) _3) $ \(uid, mbNoteKey) ->
|
||||||
maybeEmpty mbNoteKey $ const $
|
maybeEmpty mbNoteKey $ const $
|
||||||
anchorCellM (courseLink <$> encrypt uid) (hasComment True)
|
anchorCellM (courseLink <$> encrypt uid) (hasComment True)
|
||||||
where
|
where
|
||||||
@ -191,15 +191,15 @@ colUserSubmissionGroup = sortable (Just "submission-group") (i18nCell MsgSubmiss
|
|||||||
colUserSheets :: forall m c. IsDBTable m c => [SheetName] -> Cornice Sortable ('Cap 'Base) UserTableData (DBCell m c)
|
colUserSheets :: forall m c. IsDBTable m c => [SheetName] -> Cornice Sortable ('Cap 'Base) UserTableData (DBCell m c)
|
||||||
colUserSheets shns = cap (Sortable Nothing caption) $ foldMap userSheetCol shns
|
colUserSheets shns = cap (Sortable Nothing caption) $ foldMap userSheetCol shns
|
||||||
where
|
where
|
||||||
caption = i18nCell MsgCourseUserSheets
|
caption = i18nCell MsgCourseUserSheets
|
||||||
& cellAttrs <>~ [ ("uw-hide-column-header", "sheets")
|
& cellAttrs <>~ [ ("uw-hide-column-header", "sheets")
|
||||||
, ("uw-hide-column-default-hidden", "")
|
, ("uw-hide-column-default-hidden", "")
|
||||||
]
|
]
|
||||||
|
|
||||||
userSheetCol :: SheetName -> Colonnade Sortable UserTableData (DBCell m c)
|
userSheetCol :: SheetName -> Colonnade Sortable UserTableData (DBCell m c)
|
||||||
userSheetCol shn = sortable (Just . SortingKey $ "sheet-" <> shn) (i18nCell shn) . views (_userSheets . at shn) $ \case
|
userSheetCol shn = sortable (Just . SortingKey $ "sheet-" <> shn) (i18nCell shn) . views (_userSheets . at shn) $ \case
|
||||||
Just (preview _grading -> Just Points{..}, Just points) -> i18nCell $ MsgAchievedOf points maxPoints
|
Just (preview _grading -> Just Points{..}, Just points) -> i18nCell $ MsgAchievedOf points maxPoints
|
||||||
Just (preview _grading -> Just grading', Just points) -> i18nCell . bool MsgNotPassed MsgPassed . fromMaybe False $ gradingPassed grading' points
|
Just (preview _grading -> Just grading', Just points) -> i18nCell . bool MsgNotPassed MsgPassed $ Just True == gradingPassed grading' points
|
||||||
_other -> mempty
|
_other -> mempty
|
||||||
|
|
||||||
|
|
||||||
@ -210,7 +210,7 @@ data UserTableCsvStudyFeature = UserTableCsvStudyFeature
|
|||||||
, csvUserType :: StudyFieldType
|
, csvUserType :: StudyFieldType
|
||||||
} deriving (Eq, Ord, Read, Show, Generic, Typeable)
|
} deriving (Eq, Ord, Read, Show, Generic, Typeable)
|
||||||
makeLenses_ ''UserTableCsvStudyFeature
|
makeLenses_ ''UserTableCsvStudyFeature
|
||||||
|
|
||||||
data UserTableCsv = UserTableCsv
|
data UserTableCsv = UserTableCsv
|
||||||
{ csvUserName :: Text
|
{ csvUserName :: Text
|
||||||
, csvUserSex :: Maybe Sex
|
, csvUserSex :: Maybe Sex
|
||||||
@ -404,33 +404,33 @@ makeCourseUserTable cid acts restrict colChoices psValidator csvColumns = do
|
|||||||
, single $ sortUserEmail queryUser
|
, single $ sortUserEmail queryUser
|
||||||
, single $ sortUserMatriclenr queryUser
|
, single $ sortUserMatriclenr queryUser
|
||||||
, sortUserSex (to queryUser . to (E.^. UserSex))
|
, sortUserSex (to queryUser . to (E.^. UserSex))
|
||||||
, single $ ("degree" , SortColumn $ queryFeaturesDegree >>> (E.?. StudyDegreeName))
|
, single ("degree" , SortColumn $ queryFeaturesDegree >>> (E.?. StudyDegreeName))
|
||||||
, single $ ("degree-short", SortColumn $ queryFeaturesDegree >>> (E.?. StudyDegreeShorthand))
|
, single ("degree-short", SortColumn $ queryFeaturesDegree >>> (E.?. StudyDegreeShorthand))
|
||||||
, single $ ("field" , SortColumn $ queryFeaturesField >>> (E.?. StudyTermsName))
|
, single ("field" , SortColumn $ queryFeaturesField >>> (E.?. StudyTermsName))
|
||||||
, single $ ("field-short" , SortColumn $ queryFeaturesField >>> (E.?. StudyTermsShorthand))
|
, single ("field-short" , SortColumn $ queryFeaturesField >>> (E.?. StudyTermsShorthand))
|
||||||
, single $ ("semesternr" , SortColumn $ queryFeaturesStudy >>> (E.?. StudyFeaturesSemester))
|
, single ("semesternr" , SortColumn $ queryFeaturesStudy >>> (E.?. StudyFeaturesSemester))
|
||||||
, single $ ("registration", SortColumn $ queryParticipant >>> (E.^. CourseParticipantRegistration))
|
, single ("registration", SortColumn $ queryParticipant >>> (E.^. CourseParticipantRegistration))
|
||||||
, single $ ("note" , SortColumn $ queryUserNote >>> \note -> -- sort by last edit date
|
, single ("note" , SortColumn $ queryUserNote >>> \note -> -- sort by last edit date
|
||||||
E.subSelectMaybe . E.from $ \edit -> do
|
E.subSelectMaybe . E.from $ \edit -> do
|
||||||
E.where_ $ note E.?. CourseUserNoteId E.==. E.just (edit E.^. CourseUserNoteEditNote)
|
E.where_ $ note E.?. CourseUserNoteId E.==. E.just (edit E.^. CourseUserNoteEditNote)
|
||||||
return . E.max_ $ edit E.^. CourseUserNoteEditTime
|
return . E.max_ $ edit E.^. CourseUserNoteEditTime
|
||||||
)
|
)
|
||||||
, single $ ("tutorials" , SortColumn $ queryUser >>> \user ->
|
, single ("tutorials" , SortColumn $ queryUser >>> \user ->
|
||||||
E.subSelectMaybe . E.from $ \(tutorial `E.InnerJoin` participant) -> do
|
E.subSelectMaybe . E.from $ \(tutorial `E.InnerJoin` participant) -> do
|
||||||
E.on $ tutorial E.^. TutorialId E.==. participant E.^. TutorialParticipantTutorial
|
E.on $ tutorial E.^. TutorialId E.==. participant E.^. TutorialParticipantTutorial
|
||||||
E.&&. tutorial E.^. TutorialCourse E.==. E.val cid
|
E.&&. tutorial E.^. TutorialCourse E.==. E.val cid
|
||||||
E.where_ $ participant E.^. TutorialParticipantUser E.==. user E.^. UserId
|
E.where_ $ participant E.^. TutorialParticipantUser E.==. user E.^. UserId
|
||||||
return . E.min_ $ tutorial E.^. TutorialName
|
return . E.min_ $ tutorial E.^. TutorialName
|
||||||
)
|
)
|
||||||
, single $ ("exams" , SortColumn $ queryUser >>> \user ->
|
, single ("exams" , SortColumn $ queryUser >>> \user ->
|
||||||
E.subSelectMaybe . E.from $ \(exam `E.InnerJoin` examRegistration) -> do
|
E.subSelectMaybe . E.from $ \(exam `E.InnerJoin` examRegistration) -> do
|
||||||
E.on $ exam E.^. ExamId E.==. examRegistration E.^. ExamRegistrationExam
|
E.on $ exam E.^. ExamId E.==. examRegistration E.^. ExamRegistrationExam
|
||||||
E.&&. exam E.^. ExamCourse E.==. E.val cid
|
E.&&. exam E.^. ExamCourse E.==. E.val cid
|
||||||
E.where_ $ examRegistration E.^. ExamRegistrationUser E.==. user E.^. UserId
|
E.where_ $ examRegistration E.^. ExamRegistrationUser E.==. user E.^. UserId
|
||||||
return . E.min_ $ exam E.^. ExamName
|
return . E.min_ $ exam E.^. ExamName
|
||||||
)
|
)
|
||||||
, single $ ("submission-group", SortColumn $ querySubmissionGroup >>> (E.?. SubmissionGroupName))
|
, single ("submission-group", SortColumn $ querySubmissionGroup >>> (E.?. SubmissionGroupName))
|
||||||
, single $ ("state", SortColumn $ queryParticipant >>> (E.^. CourseParticipantState))
|
, single ("state", SortColumn $ queryParticipant >>> (E.^. CourseParticipantState))
|
||||||
, mconcat
|
, mconcat
|
||||||
[ single ( SortingKey $ "sheet-" <> sheetName
|
[ single ( SortingKey $ "sheet-" <> sheetName
|
||||||
, SortColumn $ \(queryUser -> user) -> E.subSelectMaybe . E.from $ \(submission `E.InnerJoin` submissionUser) -> do
|
, SortColumn $ \(queryUser -> user) -> E.subSelectMaybe . E.from $ \(submission `E.InnerJoin` submissionUser) -> do
|
||||||
@ -438,8 +438,8 @@ makeCourseUserTable cid acts restrict colChoices psValidator csvColumns = do
|
|||||||
E.where_ $ submissionUser E.^. SubmissionUserUser E.==. user E.^. UserId
|
E.where_ $ submissionUser E.^. SubmissionUserUser E.==. user E.^. UserId
|
||||||
E.where_ $ submission E.^. SubmissionSheet E.==. E.val shId
|
E.where_ $ submission E.^. SubmissionSheet E.==. E.val shId
|
||||||
return $ submission E.^. SubmissionRatingPoints
|
return $ submission E.^. SubmissionRatingPoints
|
||||||
|
|
||||||
)
|
)
|
||||||
| Entity shId Sheet{..} <- sheets
|
| Entity shId Sheet{..} <- sheets
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
@ -450,28 +450,28 @@ makeCourseUserTable cid acts restrict colChoices psValidator csvColumns = do
|
|||||||
, single $ fltrUserMatriclenr queryUser
|
, single $ fltrUserMatriclenr queryUser
|
||||||
, single $ fltrUserNameEmail queryUser
|
, single $ fltrUserNameEmail queryUser
|
||||||
, fltrUserSex (to queryUser . to (E.^. UserSex))
|
, fltrUserSex (to queryUser . to (E.^. UserSex))
|
||||||
, single $ ("field-name" , FilterColumn $ E.mkContainsFilter $ queryFeaturesField >>> (E.?. StudyTermsName))
|
, single ("field-name" , FilterColumn $ E.mkContainsFilter $ queryFeaturesField >>> (E.?. StudyTermsName))
|
||||||
, single $ ("field-short" , FilterColumn $ E.mkContainsFilter $ queryFeaturesField >>> (E.?. StudyTermsShorthand))
|
, single ("field-short" , FilterColumn $ E.mkContainsFilter $ queryFeaturesField >>> (E.?. StudyTermsShorthand))
|
||||||
, single $ ("field-key" , FilterColumn $ E.mkExactFilter $ queryFeaturesField >>> (E.?. StudyTermsKey))
|
, single ("field-key" , FilterColumn $ E.mkExactFilter $ queryFeaturesField >>> (E.?. StudyTermsKey))
|
||||||
, single $ ("field" , FilterColumn $ E.anyFilter
|
, single ("field" , FilterColumn $ E.anyFilter
|
||||||
[ E.mkContainsFilterWith Just $ queryFeaturesField >>> E.joinV . (E.?. StudyTermsName)
|
[ E.mkContainsFilterWith Just $ queryFeaturesField >>> E.joinV . (E.?. StudyTermsName)
|
||||||
, E.mkContainsFilterWith Just $ queryFeaturesField >>> E.joinV . (E.?. StudyTermsShorthand)
|
, E.mkContainsFilterWith Just $ queryFeaturesField >>> E.joinV . (E.?. StudyTermsShorthand)
|
||||||
, E.mkExactFilterWith readMay $ queryFeaturesField >>> (E.?. StudyTermsKey)
|
, E.mkExactFilterWith readMay $ queryFeaturesField >>> (E.?. StudyTermsKey)
|
||||||
] )
|
] )
|
||||||
, single $ ("degree" , FilterColumn $ E.anyFilter
|
, single ("degree" , FilterColumn $ E.anyFilter
|
||||||
[ E.mkContainsFilterWith Just $ queryFeaturesDegree >>> E.joinV . (E.?. StudyDegreeName)
|
[ E.mkContainsFilterWith Just $ queryFeaturesDegree >>> E.joinV . (E.?. StudyDegreeName)
|
||||||
, E.mkContainsFilterWith Just $ queryFeaturesDegree >>> E.joinV . (E.?. StudyDegreeShorthand)
|
, E.mkContainsFilterWith Just $ queryFeaturesDegree >>> E.joinV . (E.?. StudyDegreeShorthand)
|
||||||
, E.mkExactFilterWith readMay $ queryFeaturesDegree >>> (E.?. StudyDegreeKey)
|
, E.mkExactFilterWith readMay $ queryFeaturesDegree >>> (E.?. StudyDegreeKey)
|
||||||
] )
|
] )
|
||||||
, single $ ("semesternr" , FilterColumn $ E.mkExactFilter $ queryFeaturesStudy >>> (E.?. StudyFeaturesSemester))
|
, single ("semesternr" , FilterColumn $ E.mkExactFilter $ queryFeaturesStudy >>> (E.?. StudyFeaturesSemester))
|
||||||
, single $ ("tutorial" , FilterColumn $ E.mkExistsFilter $ \row criterion ->
|
, single ("tutorial" , FilterColumn $ E.mkExistsFilter $ \row criterion ->
|
||||||
E.from $ \(tutorial `E.InnerJoin` tutorialParticipant) -> do
|
E.from $ \(tutorial `E.InnerJoin` tutorialParticipant) -> do
|
||||||
E.on $ tutorial E.^. TutorialId E.==. tutorialParticipant E.^. TutorialParticipantTutorial
|
E.on $ tutorial E.^. TutorialId E.==. tutorialParticipant E.^. TutorialParticipantTutorial
|
||||||
E.where_ $ tutorial E.^. TutorialCourse E.==. E.val cid
|
E.where_ $ tutorial E.^. TutorialCourse E.==. E.val cid
|
||||||
E.&&. E.hasInfix (tutorial E.^. TutorialName) (E.val criterion :: E.SqlExpr (E.Value (CI Text)))
|
E.&&. E.hasInfix (tutorial E.^. TutorialName) (E.val criterion :: E.SqlExpr (E.Value (CI Text)))
|
||||||
E.&&. tutorialParticipant E.^. TutorialParticipantUser E.==. queryUser row E.^. UserId
|
E.&&. tutorialParticipant E.^. TutorialParticipantUser E.==. queryUser row E.^. UserId
|
||||||
)
|
)
|
||||||
, single $ ("exam" , FilterColumn $ E.mkExistsFilter $ \row criterion ->
|
, single ("exam" , FilterColumn $ E.mkExistsFilter $ \row criterion ->
|
||||||
E.from $ \(exam `E.InnerJoin` examRegistration) -> do
|
E.from $ \(exam `E.InnerJoin` examRegistration) -> do
|
||||||
E.on $ exam E.^. ExamId E.==. examRegistration E.^. ExamRegistrationExam
|
E.on $ exam E.^. ExamId E.==. examRegistration E.^. ExamRegistrationExam
|
||||||
E.where_ $ exam E.^. ExamCourse E.==. E.val cid
|
E.where_ $ exam E.^. ExamCourse E.==. E.val cid
|
||||||
@ -480,15 +480,15 @@ makeCourseUserTable cid acts restrict colChoices psValidator csvColumns = do
|
|||||||
)
|
)
|
||||||
-- , ("course-registration", error "TODO") -- TODO
|
-- , ("course-registration", error "TODO") -- TODO
|
||||||
-- , ("course-user-note", error "TODO") -- TODO
|
-- , ("course-user-note", error "TODO") -- TODO
|
||||||
, single $ ("submission-group", FilterColumn $ E.mkContainsFilter $ querySubmissionGroup >>> (E.?. SubmissionGroupName))
|
, single ("submission-group", FilterColumn $ E.mkContainsFilter $ querySubmissionGroup >>> (E.?. SubmissionGroupName))
|
||||||
, single $ ("active", FilterColumn $ E.mkExactFilter $ queryParticipant >>> (E.==. E.val CourseParticipantActive) . (E.^. CourseParticipantState))
|
, single ("active", FilterColumn $ E.mkExactFilter $ queryParticipant >>> (E.==. E.val CourseParticipantActive) . (E.^. CourseParticipantState))
|
||||||
, single $ ("has-personalised-sheet-files", FilterColumn $ \t (Last criterion) -> flip (maybe E.true) criterion $ \shn
|
, single ("has-personalised-sheet-files", FilterColumn $ \t (Last criterion) -> flip (maybe E.true) criterion $ \shn
|
||||||
-> E.exists . E.from $ \(psFile `E.InnerJoin` sheet) -> do
|
-> E.exists . E.from $ \(psFile `E.InnerJoin` sheet) -> do
|
||||||
E.on $ psFile E.^. PersonalisedSheetFileSheet E.==. sheet E.^. SheetId
|
E.on $ psFile E.^. PersonalisedSheetFileSheet E.==. sheet E.^. SheetId
|
||||||
E.where_ $ psFile E.^. PersonalisedSheetFileUser E.==. queryParticipant t E.^. CourseParticipantUser
|
E.where_ $ psFile E.^. PersonalisedSheetFileUser E.==. queryParticipant t E.^. CourseParticipantUser
|
||||||
E.where_ $ sheet E.^. SheetCourse E.==. E.val cid
|
E.where_ $ sheet E.^. SheetCourse E.==. E.val cid
|
||||||
E.&&. sheet E.^. SheetName E.==. E.val shn
|
E.&&. sheet E.^. SheetName E.==. E.val shn
|
||||||
)
|
)
|
||||||
]
|
]
|
||||||
where single = uncurry Map.singleton
|
where single = uncurry Map.singleton
|
||||||
dbtFilterUI mPrev = mconcat $
|
dbtFilterUI mPrev = mconcat $
|
||||||
@ -525,7 +525,7 @@ makeCourseUserTable cid acts restrict colChoices psValidator csvColumns = do
|
|||||||
{ dbtCsvExportForm = UserCsvExportData
|
{ dbtCsvExportForm = UserCsvExportData
|
||||||
<$> apopt checkBoxField (fslI MsgUserSimplifiedFeaturesOfStudyCsv & setTooltip MsgUserSimplifiedFeaturesOfStudyCsvTip) (Just $ csvUserSimplifiedFeaturesOfStudy def)
|
<$> apopt checkBoxField (fslI MsgUserSimplifiedFeaturesOfStudyCsv & setTooltip MsgUserSimplifiedFeaturesOfStudyCsvTip) (Just $ csvUserSimplifiedFeaturesOfStudy def)
|
||||||
<*> apopt checkBoxField (fslI MsgCourseUserCsvIncludeSheets & setTooltip MsgCourseUserCsvIncludeSheetsTip) (Just $ csvUserIncludeSheets def)
|
<*> apopt checkBoxField (fslI MsgCourseUserCsvIncludeSheets & setTooltip MsgCourseUserCsvIncludeSheetsTip) (Just $ csvUserIncludeSheets def)
|
||||||
, dbtCsvDoEncode = \UserCsvExportData{..} -> C.mapM $ \(E.Value uid, row) -> flip runReaderT row $
|
, dbtCsvDoEncode = \UserCsvExportData{..} -> C.mapM $ \(E.Value uid, row) -> flip runReaderT row $
|
||||||
UserTableCsv
|
UserTableCsv
|
||||||
<$> view (hasUser . _userDisplayName)
|
<$> view (hasUser . _userDisplayName)
|
||||||
<*> view (hasUser . _userSex)
|
<*> view (hasUser . _userSex)
|
||||||
@ -652,7 +652,7 @@ postCUsersR tid ssh csh = do
|
|||||||
hasExams = not $ null exams
|
hasExams = not $ null exams
|
||||||
examOccActs :: Map ExamId (AForm Handler (ExamId, Maybe ExamOccurrenceId))
|
examOccActs :: Map ExamId (AForm Handler (ExamId, Maybe ExamOccurrenceId))
|
||||||
examOccActs = examOccurrencesPerExam
|
examOccActs = examOccurrencesPerExam
|
||||||
& (map (bimap entityKey hoistMaybe))
|
& map (bimap entityKey hoistMaybe)
|
||||||
& Map.fromListWith (<>)
|
& Map.fromListWith (<>)
|
||||||
& imap (\k v -> case v of
|
& imap (\k v -> case v of
|
||||||
[] -> pure (k, Nothing)
|
[] -> pure (k, Nothing)
|
||||||
@ -726,7 +726,7 @@ postCUsersR tid ssh csh = do
|
|||||||
addMessageI Success $ MsgCourseUsersDeregistered nrDel
|
addMessageI Success $ MsgCourseUsersDeregistered nrDel
|
||||||
redirect $ CourseR tid ssh csh CUsersR
|
redirect $ CourseR tid ssh csh CUsersR
|
||||||
(CourseUserRegisterTutorialData{..}, selectedUsers) -> do
|
(CourseUserRegisterTutorialData{..}, selectedUsers) -> do
|
||||||
runDB . forM_ selectedUsers $
|
runDB . forM_ selectedUsers $
|
||||||
void . insertUnique . TutorialParticipant registerTutorial
|
void . insertUnique . TutorialParticipant registerTutorial
|
||||||
addMessageI Success . MsgCourseUsersTutorialRegistered . fromIntegral $ Set.size selectedUsers
|
addMessageI Success . MsgCourseUsersTutorialRegistered . fromIntegral $ Set.size selectedUsers
|
||||||
redirect $ CourseR tid ssh csh CUsersR
|
redirect $ CourseR tid ssh csh CUsersR
|
||||||
@ -767,7 +767,7 @@ postCUsersR tid ssh csh = do
|
|||||||
]
|
]
|
||||||
[ CourseParticipantState =. CourseParticipantActive
|
[ CourseParticipantState =. CourseParticipantActive
|
||||||
, CourseParticipantRegistration =. now
|
, CourseParticipantRegistration =. now
|
||||||
, CourseParticipantAllocated =. Nothing
|
, CourseParticipantAllocated =. Nothing
|
||||||
]
|
]
|
||||||
guard $ didUpdate > 0
|
guard $ didUpdate > 0
|
||||||
lift $ deleteWhere [ AllocationDeregisterCourse ==. Just cid, AllocationDeregisterUser ==. uid ]
|
lift $ deleteWhere [ AllocationDeregisterCourse ==. Just cid, AllocationDeregisterUser ==. uid ]
|
||||||
|
|||||||
@ -62,7 +62,7 @@ instance (CryptoRoute ciphertext plaintext, Dispatch ciphertext ps) => Dispatch
|
|||||||
handleCryptoID :: CryptoIDError -> Handler (Maybe a)
|
handleCryptoID :: CryptoIDError -> Handler (Maybe a)
|
||||||
handleCryptoID _ = return Nothing
|
handleCryptoID _ = return Nothing
|
||||||
dispatchTail = dispatchID (Proxy :: Proxy ps) ciphertext
|
dispatchTail = dispatchID (Proxy :: Proxy ps) ciphertext
|
||||||
|
|
||||||
|
|
||||||
getCryptoUUIDDispatchR :: UUID -> Handler ()
|
getCryptoUUIDDispatchR :: UUID -> Handler ()
|
||||||
getCryptoUUIDDispatchR uuid = dispatchID p uuid >>= maybe notFound (redirectAccessWith movedPermanently301)
|
getCryptoUUIDDispatchR uuid = dispatchID p uuid >>= maybe notFound (redirectAccessWith movedPermanently301)
|
||||||
@ -75,5 +75,5 @@ getCryptoUUIDDispatchR uuid = dispatchID p uuid >>= maybe notFound (redirectAcce
|
|||||||
getCryptoFileNameDispatchR :: CI FilePath -> Handler ()
|
getCryptoFileNameDispatchR :: CI FilePath -> Handler ()
|
||||||
getCryptoFileNameDispatchR path = dispatchID p path >>= maybe notFound (redirectAccessWith movedPermanently301)
|
getCryptoFileNameDispatchR path = dispatchID p path >>= maybe notFound (redirectAccessWith movedPermanently301)
|
||||||
where
|
where
|
||||||
p :: Proxy '[ SubmissionId ]
|
p :: Proxy '[ SubmissionId ]
|
||||||
p = Proxy
|
p = Proxy
|
||||||
|
|||||||
@ -8,15 +8,15 @@ import Handler.Exam.RegistrationInvite
|
|||||||
import Handler.Utils
|
import Handler.Utils
|
||||||
import Handler.Utils.Exam
|
import Handler.Utils.Exam
|
||||||
import Handler.Utils.Invitations
|
import Handler.Utils.Invitations
|
||||||
|
|
||||||
import qualified Data.Set as Set
|
import qualified Data.Set as Set
|
||||||
|
|
||||||
import Data.Semigroup (Option(..))
|
import Data.Semigroup (Option(..))
|
||||||
|
|
||||||
import Control.Monad.Error.Class (MonadError(..))
|
import Control.Monad.Error.Class (MonadError(..))
|
||||||
|
|
||||||
import Jobs.Queue
|
import Jobs.Queue
|
||||||
|
|
||||||
import Generics.Deriving.Monoid
|
import Generics.Deriving.Monoid
|
||||||
|
|
||||||
|
|
||||||
@ -43,7 +43,7 @@ postEAddUserR tid ssh csh examn = do
|
|||||||
((usersToEnlist,formWgt),formEncoding) <- runFormPost . renderWForm FormStandard $ do
|
((usersToEnlist,formWgt),formEncoding) <- runFormPost . renderWForm FormStandard $ do
|
||||||
now <- liftIO getCurrentTime
|
now <- liftIO getCurrentTime
|
||||||
occurrences <- liftHandler . runDB $ selectList [ExamOccurrenceExam ==. eid] []
|
occurrences <- liftHandler . runDB $ selectList [ExamOccurrenceExam ==. eid] []
|
||||||
|
|
||||||
let
|
let
|
||||||
localNow = utcToLocalTime now
|
localNow = utcToLocalTime now
|
||||||
tomorrowEndOfDay = case localTimeToUTC (LocalTime (addDays 2 $ localDay localNow) midnight) of
|
tomorrowEndOfDay = case localTimeToUTC (LocalTime (addDays 2 $ localDay localNow) midnight) of
|
||||||
@ -65,7 +65,7 @@ postEAddUserR tid ssh csh examn = do
|
|||||||
= max tomorrowEndOfDay earliestDate'
|
= max tomorrowEndOfDay earliestDate'
|
||||||
| otherwise
|
| otherwise
|
||||||
= tomorrowEndOfDay
|
= tomorrowEndOfDay
|
||||||
|
|
||||||
deadline <- wreq utcTimeField (fslI MsgExamRegistrationInviteDeadline) (Just defDeadline)
|
deadline <- wreq utcTimeField (fslI MsgExamRegistrationInviteDeadline) (Just defDeadline)
|
||||||
enlist <- wpopt checkBoxField (fslI MsgExamRegistrationEnlistDirectly & setTooltip MsgExamRegistrationEnlistDirectlyTip) (Just False)
|
enlist <- wpopt checkBoxField (fslI MsgExamRegistrationEnlistDirectly & setTooltip MsgExamRegistrationEnlistDirectlyTip) (Just False)
|
||||||
registerCourse <- wpopt checkBoxField (fslI MsgExamRegistrationRegisterCourse & setTooltip MsgExamRegistrationRegisterCourseTip) (Just False)
|
registerCourse <- wpopt checkBoxField (fslI MsgExamRegistrationRegisterCourse & setTooltip MsgExamRegistrationRegisterCourseTip) (Just False)
|
||||||
@ -132,7 +132,7 @@ postEAddUserR tid ssh csh examn = do
|
|||||||
lift $ lift examRegister
|
lift $ lift examRegister
|
||||||
throwError $ mempty { aurSuccess = pure userEmail }
|
throwError $ mempty { aurSuccess = pure userEmail }
|
||||||
|
|
||||||
unless registerCourse $
|
unless registerCourse $
|
||||||
throwError $ mempty { aurNoCourseRegistration = pure userEmail }
|
throwError $ mempty { aurNoCourseRegistration = pure userEmail }
|
||||||
|
|
||||||
guardAuthResult =<< lift (lift $ evalAccessDB (CourseR tid ssh csh CAddUserR) True)
|
guardAuthResult =<< lift (lift $ evalAccessDB (CourseR tid ssh csh CAddUserR) True)
|
||||||
|
|||||||
@ -52,7 +52,7 @@ examAutoOccurrenceCalculateForm :: ExamAutoOccurrenceCalculateForm -> Form ExamA
|
|||||||
examAutoOccurrenceCalculateForm ExamAutoOccurrenceCalculateForm{ eaofConfig }
|
examAutoOccurrenceCalculateForm ExamAutoOccurrenceCalculateForm{ eaofConfig }
|
||||||
= identifyForm FIDExamAutoOccurrenceCalculate . renderAForm FormStandard $ ExamAutoOccurrenceCalculateForm <$> eaocForm
|
= identifyForm FIDExamAutoOccurrenceCalculate . renderAForm FormStandard $ ExamAutoOccurrenceCalculateForm <$> eaocForm
|
||||||
where
|
where
|
||||||
eaocForm =
|
eaocForm =
|
||||||
(set _eaocMinimizeRooms <$> apopt checkBoxField (fslI MsgExamAutoOccurrenceMinimizeRooms & setTooltip MsgExamAutoOccurrenceMinimizeRoomsTip) (Just $ eaofConfig ^. _eaocMinimizeRooms))
|
(set _eaocMinimizeRooms <$> apopt checkBoxField (fslI MsgExamAutoOccurrenceMinimizeRooms & setTooltip MsgExamAutoOccurrenceMinimizeRoomsTip) (Just $ eaofConfig ^. _eaocMinimizeRooms))
|
||||||
<*> pure def
|
<*> pure def
|
||||||
|
|
||||||
@ -62,7 +62,7 @@ examAutoOccurrenceNudgeForm occId protoForm html = do
|
|||||||
(btnRes, wgt) <- identifyForm (FIDExamAutoOccurrenceNudge $ ciphertext cID) (buttonForm' [BtnExamAutoOccurrenceNudgeUp, BtnExamAutoOccurrenceNudgeDown]) html
|
(btnRes, wgt) <- identifyForm (FIDExamAutoOccurrenceNudge $ ciphertext cID) (buttonForm' [BtnExamAutoOccurrenceNudgeUp, BtnExamAutoOccurrenceNudgeDown]) html
|
||||||
oldDataRes <- globalPostParamField PostExamAutoOccurrencePrevious secretJsonField
|
oldDataRes <- globalPostParamField PostExamAutoOccurrencePrevious secretJsonField
|
||||||
oldDataId <- newIdent
|
oldDataId <- newIdent
|
||||||
|
|
||||||
let protoForm' = fromMaybe def $ oldDataRes <|> protoForm
|
let protoForm' = fromMaybe def $ oldDataRes <|> protoForm
|
||||||
genForm btn = protoForm' & _eaofConfig . _eaocNudge %~ Map.insertWith (+) occId n
|
genForm btn = protoForm' & _eaofConfig . _eaocNudge %~ Map.insertWith (+) occId n
|
||||||
where n = case btn of
|
where n = case btn of
|
||||||
@ -83,12 +83,12 @@ examAutoOccurrenceAcceptForm confirmData = identifyForm FIDExamAutoOccurrenceCon
|
|||||||
examAutoOccurrenceCalculateWidget :: TermId -> SchoolId -> CourseShorthand -> ExamName -> Widget
|
examAutoOccurrenceCalculateWidget :: TermId -> SchoolId -> CourseShorthand -> ExamName -> Widget
|
||||||
examAutoOccurrenceCalculateWidget tid ssh csh examn = do
|
examAutoOccurrenceCalculateWidget tid ssh csh examn = do
|
||||||
(formView, formEncoding) <- liftHandler . generateFormPost $ examAutoOccurrenceCalculateForm def
|
(formView, formEncoding) <- liftHandler . generateFormPost $ examAutoOccurrenceCalculateForm def
|
||||||
|
|
||||||
wrapForm' BtnExamAutoOccurrenceCalculate $(i18nWidgetFile "exam-auto-occurrence-calculate") def
|
wrapForm' BtnExamAutoOccurrenceCalculate $(i18nWidgetFile "exam-auto-occurrence-calculate") def
|
||||||
{ formAction = Just . SomeRoute $ CExamR tid ssh csh examn EAutoOccurrenceR
|
{ formAction = Just . SomeRoute $ CExamR tid ssh csh examn EAutoOccurrenceR
|
||||||
, formEncoding
|
, formEncoding
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
postEAutoOccurrenceR :: TermId -> SchoolId -> CourseShorthand -> ExamName -> Handler Html
|
postEAutoOccurrenceR :: TermId -> SchoolId -> CourseShorthand -> ExamName -> Handler Html
|
||||||
postEAutoOccurrenceR tid ssh csh examn = do
|
postEAutoOccurrenceR tid ssh csh examn = do
|
||||||
@ -96,8 +96,8 @@ postEAutoOccurrenceR tid ssh csh examn = do
|
|||||||
exam@(Entity eId _) <- fetchExam tid ssh csh examn
|
exam@(Entity eId _) <- fetchExam tid ssh csh examn
|
||||||
occurrences <- selectList [ ExamOccurrenceExam ==. eId ] [ Asc ExamOccurrenceName ]
|
occurrences <- selectList [ ExamOccurrenceExam ==. eId ] [ Asc ExamOccurrenceName ]
|
||||||
return (exam, occurrences)
|
return (exam, occurrences)
|
||||||
|
|
||||||
|
|
||||||
((calculateRes, _), _) <- runFormPost $ examAutoOccurrenceCalculateForm def
|
((calculateRes, _), _) <- runFormPost $ examAutoOccurrenceCalculateForm def
|
||||||
|
|
||||||
nudgeRes <- sequence . flip Map.fromSet (setOf (folded . _entityKey) occurrences) $ \occId ->
|
nudgeRes <- sequence . flip Map.fromSet (setOf (folded . _entityKey) occurrences) $ \occId ->
|
||||||
|
|||||||
@ -84,15 +84,15 @@ getECorrectR tid ssh csh examn = do
|
|||||||
return (exam, entityVal <$> examParts)
|
return (exam, entityVal <$> examParts)
|
||||||
|
|
||||||
mayEditResults <- hasWriteAccessTo $ CExamR tid ssh csh examn EUsersR
|
mayEditResults <- hasWriteAccessTo $ CExamR tid ssh csh examn EUsersR
|
||||||
|
|
||||||
let
|
let
|
||||||
heading = prependCourseTitle tid ssh csh $ (mr . MsgExamCorrectHeading . CI.original) examName
|
heading = prependCourseTitle tid ssh csh $ (mr . MsgExamCorrectHeading . CI.original) examName
|
||||||
|
|
||||||
ptsInput :: ExamPartNumber -> Widget
|
ptsInput :: ExamPartNumber -> Widget
|
||||||
ptsInput n = do
|
ptsInput n = do
|
||||||
name <- newIdent
|
name <- newIdent
|
||||||
fieldView (pointsField :: Field Handler Points) ("exam-correct__" <> toPathPiece n) name [("uw-exam-correct--part-input", toPathPiece n)] (Left "") False
|
fieldView (pointsField :: Field Handler Points) ("exam-correct__" <> toPathPiece n) name [("uw-exam-correct--part-input", toPathPiece n)] (Left "") False
|
||||||
|
|
||||||
examGrades :: [ExamGrade]
|
examGrades :: [ExamGrade]
|
||||||
examGrades = universeF
|
examGrades = universeF
|
||||||
|
|
||||||
@ -111,12 +111,12 @@ postECorrectR tid ssh csh examn = do
|
|||||||
CorrectInterfaceRequest{..} <- requireCheckJsonBody
|
CorrectInterfaceRequest{..} <- requireCheckJsonBody
|
||||||
|
|
||||||
mayEditResults <- hasWriteAccessTo $ CExamR tid ssh csh examn EUsersR
|
mayEditResults <- hasWriteAccessTo $ CExamR tid ssh csh examn EUsersR
|
||||||
|
|
||||||
response <- runDB . exceptT (<$ transactionUndo) return $ do
|
response <- runDB . exceptT (<$ transactionUndo) return $ do
|
||||||
Entity eId Exam{..} <- lift $ fetchExam tid ssh csh examn
|
Entity eId Exam{} <- lift $ fetchExam tid ssh csh examn
|
||||||
euid <- traverse decrypt ciqUser
|
euid <- traverse decrypt ciqUser
|
||||||
|
|
||||||
guardMExceptT (maybe True ((>= 3) . length) $ euid ^? _Left) $
|
guardMExceptT (maybe True ((>= 3) . length) $ euid ^? _Left) $
|
||||||
CorrectInterfaceResponseFailure Nothing <$> (getMessageRender <*> pure MsgExamCorrectErrorNeedleTooShort)
|
CorrectInterfaceResponseFailure Nothing <$> (getMessageRender <*> pure MsgExamCorrectErrorNeedleTooShort)
|
||||||
|
|
||||||
|
|
||||||
@ -188,7 +188,7 @@ postECorrectR tid ssh csh examn = do
|
|||||||
in CorrectInterfaceResponseFailure
|
in CorrectInterfaceResponseFailure
|
||||||
<$> (Just <$> userToResponse match)
|
<$> (Just <$> userToResponse match)
|
||||||
<*> (getMessageRender <*> pure msg)
|
<*> (getMessageRender <*> pure msg)
|
||||||
|
|
||||||
newExamPartResult <- lift $ upsert ExamPartResult
|
newExamPartResult <- lift $ upsert ExamPartResult
|
||||||
{ examPartResultExamPart = examPartId
|
{ examPartResultExamPart = examPartId
|
||||||
, examPartResultUser = uid
|
, examPartResultUser = uid
|
||||||
@ -230,7 +230,7 @@ postECorrectR tid ssh csh examn = do
|
|||||||
return $ newResult ^? _entityVal . _examResultResult
|
return $ newResult ^? _entityVal . _examResultResult
|
||||||
| otherwise -> return $ mOldResult ^? _Just . _entityVal . _examResultResult
|
| otherwise -> return $ mOldResult ^? _Just . _entityVal . _examResultResult
|
||||||
| otherwise -> return Nothing
|
| otherwise -> return Nothing
|
||||||
|
|
||||||
user <- userToResponse match
|
user <- userToResponse match
|
||||||
return CorrectInterfaceResponseSuccess
|
return CorrectInterfaceResponseSuccess
|
||||||
{ cirsUser = user
|
{ cirsUser = user
|
||||||
@ -252,7 +252,7 @@ postECorrectR tid ssh csh examn = do
|
|||||||
{ ciraMessage = mr MsgExamCorrectErrorMultipleMatchingParticipants
|
{ ciraMessage = mr MsgExamCorrectErrorMultipleMatchingParticipants
|
||||||
, ciraUsers = Set.fromList users
|
, ciraUsers = Set.fromList users
|
||||||
}
|
}
|
||||||
|
|
||||||
let
|
let
|
||||||
responseStatus = case response of
|
responseStatus = case response of
|
||||||
CorrectInterfaceResponseSuccess{} -> ok200
|
CorrectInterfaceResponseSuccess{} -> ok200
|
||||||
@ -261,5 +261,5 @@ postECorrectR tid ssh csh examn = do
|
|||||||
|
|
||||||
whenM acceptsJson $
|
whenM acceptsJson $
|
||||||
sendResponseStatus responseStatus $ toJSON response
|
sendResponseStatus responseStatus $ toJSON response
|
||||||
|
|
||||||
redirect $ CExamR tid ssh csh examn EShowR
|
redirect $ CExamR tid ssh csh examn EShowR
|
||||||
|
|||||||
@ -18,7 +18,7 @@ import Data.Aeson hiding (Result(..))
|
|||||||
|
|
||||||
import qualified Data.HashSet as HashSet
|
import qualified Data.HashSet as HashSet
|
||||||
|
|
||||||
|
|
||||||
instance IsInvitableJunction ExamCorrector where
|
instance IsInvitableJunction ExamCorrector where
|
||||||
type InvitationFor ExamCorrector = Exam
|
type InvitationFor ExamCorrector = Exam
|
||||||
data InvitableJunction ExamCorrector = JunctionExamCorrector
|
data InvitableJunction ExamCorrector = JunctionExamCorrector
|
||||||
|
|||||||
@ -96,7 +96,7 @@ examForm template html = do
|
|||||||
<*> apopt checkBoxField (fslI MsgExamPublicStatistics & setTooltip MsgExamPublicStatisticsTip) (efPublicStatistics <$> template <|> Just True)
|
<*> apopt checkBoxField (fslI MsgExamPublicStatistics & setTooltip MsgExamPublicStatisticsTip) (efPublicStatistics <$> template <|> Just True)
|
||||||
<*> optionalActionA (examGradingRuleForm $ efGradingRule =<< template) (fslI MsgExamAutomaticGrading & setTooltip MsgExamAutomaticGradingTip) (is _Just . efGradingRule <$> template)
|
<*> optionalActionA (examGradingRuleForm $ efGradingRule =<< template) (fslI MsgExamAutomaticGrading & setTooltip MsgExamAutomaticGradingTip) (is _Just . efGradingRule <$> template)
|
||||||
<*> optionalActionA (examBonusRuleForm $ efBonusRule =<< template) (fslI MsgExamBonus) (is _Just . efBonusRule <$> template)
|
<*> optionalActionA (examBonusRuleForm $ efBonusRule =<< template) (fslI MsgExamBonus) (is _Just . efBonusRule <$> template)
|
||||||
<*> (examOccurrenceRuleForm $ efOccurrenceRule <$> template)
|
<*> examOccurrenceRuleForm (efOccurrenceRule <$> template)
|
||||||
<* aformSection MsgExamFormCorrection
|
<* aformSection MsgExamFormCorrection
|
||||||
<*> examCorrectorsForm (efCorrectors <$> template)
|
<*> examCorrectorsForm (efCorrectors <$> template)
|
||||||
<* aformSection MsgExamFormParts
|
<* aformSection MsgExamFormParts
|
||||||
@ -117,7 +117,7 @@ examCorrectorsForm mPrev = wFormToAForm $ do
|
|||||||
(addRes, addView) <- mpreq (multiUserInvitationField . MUILookupAnyUser $ Just corrUserSuggestions) (fslI MsgExamCorrectorEmail & addName (nudge "email") & addPlaceholder (mr MsgLdapIdentificationOrEmail)) Nothing
|
(addRes, addView) <- mpreq (multiUserInvitationField . MUILookupAnyUser $ Just corrUserSuggestions) (fslI MsgExamCorrectorEmail & addName (nudge "email") & addPlaceholder (mr MsgLdapIdentificationOrEmail)) Nothing
|
||||||
let
|
let
|
||||||
addRes'
|
addRes'
|
||||||
| otherwise
|
|
||||||
= addRes <&> \newDat oldDat -> if
|
= addRes <&> \newDat oldDat -> if
|
||||||
| existing <- newDat `Set.intersection` Set.fromList oldDat
|
| existing <- newDat `Set.intersection` Set.fromList oldDat
|
||||||
, not $ Set.null existing
|
, not $ Set.null existing
|
||||||
@ -201,7 +201,7 @@ examPartsForm prev = wFormToAForm $ do
|
|||||||
fmap (fmap Set.fromList) . massInputAccumEditW miAdd' miCell' miButtonAction' miLayout' miIdent' (fslI MsgExamParts) False $ Set.toList <$> prev
|
fmap (fmap Set.fromList) . massInputAccumEditW miAdd' miCell' miButtonAction' miLayout' miIdent' (fslI MsgExamParts) False $ Set.toList <$> prev
|
||||||
where
|
where
|
||||||
examPartForm' nudge mPrev csrf = do
|
examPartForm' nudge mPrev csrf = do
|
||||||
(epfIdRes, epfIdView) <- mopt hiddenField ("" & addName (nudge "id")) (Just $ epfId =<< mPrev)
|
(epfIdRes, epfIdView) <- mopt hiddenField ("" & addName (nudge "id")) (Just $ epfId =<< mPrev)
|
||||||
(epfNumberRes, epfNumberView) <- mpreq (isoField (from _ExamPartNumber) $ textField & cfStrip & cfCI) (fslI MsgExamPartNumber & addName (nudge "number") & addPlaceholder "1, 6a, 3.1.4, ...") (epfNumber <$> mPrev)
|
(epfNumberRes, epfNumberView) <- mpreq (isoField (from _ExamPartNumber) $ textField & cfStrip & cfCI) (fslI MsgExamPartNumber & addName (nudge "number") & addPlaceholder "1, 6a, 3.1.4, ...") (epfNumber <$> mPrev)
|
||||||
(epfNameRes, epfNameView) <- mopt (textField & cfStrip & cfCI) (fslI MsgExamPartName & addName (nudge "name")) (epfName <$> mPrev)
|
(epfNameRes, epfNameView) <- mopt (textField & cfStrip & cfCI) (fslI MsgExamPartName & addName (nudge "name")) (epfName <$> mPrev)
|
||||||
(epfMaxPointsRes, epfMaxPointsView) <- mopt pointsField (fslI MsgExamPartMaxPoints & addName (nudge "max-points")) (epfMaxPoints <$> mPrev)
|
(epfMaxPointsRes, epfMaxPointsView) <- mopt pointsField (fslI MsgExamPartMaxPoints & addName (nudge "max-points")) (epfMaxPoints <$> mPrev)
|
||||||
@ -221,7 +221,7 @@ examPartsForm prev = wFormToAForm $ do
|
|||||||
(res, formWidget) <- examPartForm' nudge Nothing csrf
|
(res, formWidget) <- examPartForm' nudge Nothing csrf
|
||||||
let
|
let
|
||||||
addRes = res <&> \newDat (Set.fromList -> oldDat) -> if
|
addRes = res <&> \newDat (Set.fromList -> oldDat) -> if
|
||||||
| any (\old -> fromMaybe False $ (==) <$> epfName newDat <*> epfName old) oldDat
|
| any (\old -> Just True == ((==) <$> epfName newDat <*> epfName old)) oldDat
|
||||||
-> FormFailure [mr MsgExamPartAlreadyExists]
|
-> FormFailure [mr MsgExamPartAlreadyExists]
|
||||||
| otherwise -> FormSuccess $ pure newDat
|
| otherwise -> FormSuccess $ pure newDat
|
||||||
return (addRes, $(widgetFile "widgets/massinput/examParts/add"))
|
return (addRes, $(widgetFile "widgets/massinput/examParts/add"))
|
||||||
@ -336,10 +336,10 @@ validateExam = do
|
|||||||
|
|
||||||
guardValidation MsgExamRegisterToMustBeAfterRegisterFrom $ NTop efRegisterTo >= NTop efRegisterFrom
|
guardValidation MsgExamRegisterToMustBeAfterRegisterFrom $ NTop efRegisterTo >= NTop efRegisterFrom
|
||||||
guardValidation MsgExamDeregisterUntilMustBeAfterRegisterFrom $ NTop efDeregisterUntil >= NTop efRegisterFrom
|
guardValidation MsgExamDeregisterUntilMustBeAfterRegisterFrom $ NTop efDeregisterUntil >= NTop efRegisterFrom
|
||||||
guardValidation MsgExamStartMustBeAfterPublishOccurrenceAssignments . fromMaybe True $ (>=) <$> efStart <*> efPublishOccurrenceAssignments
|
guardValidation MsgExamStartMustBeAfterPublishOccurrenceAssignments $ Just False /= ((>=) <$> efStart <*> efPublishOccurrenceAssignments)
|
||||||
guardValidation MsgExamEndMustBeAfterStart $ NTop efEnd >= NTop efStart
|
guardValidation MsgExamEndMustBeAfterStart $ NTop efEnd >= NTop efStart
|
||||||
guardValidation MsgExamFinishedMustBeAfterEnd . fromMaybe True $ (>=) <$> efFinished <*> efEnd
|
guardValidation MsgExamFinishedMustBeAfterEnd $ Just False /= ((>=) <$> efFinished <*> efEnd)
|
||||||
guardValidation MsgExamFinishedMustBeAfterStart . fromMaybe True $ (>=) <$> efFinished <*> efStart
|
guardValidation MsgExamFinishedMustBeAfterStart $ Just False /= ((>=) <$> efFinished <*> efStart)
|
||||||
|
|
||||||
forM_ efOccurrences $ \ExamOccurrenceForm{..} -> do
|
forM_ efOccurrences $ \ExamOccurrenceForm{..} -> do
|
||||||
guardValidation (MsgExamOccurrenceEndMustBeAfterStart eofName) $ NTop eofEnd >= NTop (Just eofStart)
|
guardValidation (MsgExamOccurrenceEndMustBeAfterStart eofName) $ NTop eofEnd >= NTop (Just eofStart)
|
||||||
|
|||||||
@ -6,7 +6,7 @@ module Handler.Exam.List
|
|||||||
import Import
|
import Import
|
||||||
|
|
||||||
import Handler.Utils
|
import Handler.Utils
|
||||||
|
|
||||||
import qualified Data.Map as Map
|
import qualified Data.Map as Map
|
||||||
|
|
||||||
import qualified Database.Esqueleto as E
|
import qualified Database.Esqueleto as E
|
||||||
@ -75,16 +75,15 @@ mkExamTable (Entity cid Course{..}) = do
|
|||||||
examDBTableValidator = def
|
examDBTableValidator = def
|
||||||
& defaultSorting [SortAscBy "time"]
|
& defaultSorting [SortAscBy "time"]
|
||||||
& forceFilter "may-read" (Any True)
|
& forceFilter "may-read" (Any True)
|
||||||
|
|
||||||
dbTable examDBTableValidator examDBTable
|
dbTable examDBTableValidator examDBTable
|
||||||
|
|
||||||
|
|
||||||
getCExamListR :: TermId -> SchoolId -> CourseShorthand -> Handler Html
|
getCExamListR :: TermId -> SchoolId -> CourseShorthand -> Handler Html
|
||||||
getCExamListR tid ssh csh = do
|
getCExamListR tid ssh csh = do
|
||||||
(Entity _ Course{..}, examTable) <- runDB $ do
|
examTable <- runDB $ do
|
||||||
c <- getBy404 $ TermSchoolCourseShort tid ssh csh
|
c <- getBy404 $ TermSchoolCourseShort tid ssh csh
|
||||||
(_, examTable) <- mkExamTable c
|
view _2 <$> mkExamTable c
|
||||||
return (c, examTable)
|
|
||||||
|
|
||||||
siteLayoutMsg (prependCourseTitle tid ssh csh MsgExamsHeading) $ do
|
siteLayoutMsg (prependCourseTitle tid ssh csh MsgExamsHeading) $ do
|
||||||
setTitleI $ prependCourseTitle tid ssh csh MsgExamsHeading
|
setTitleI $ prependCourseTitle tid ssh csh MsgExamsHeading
|
||||||
|
|||||||
@ -12,7 +12,7 @@ import Handler.Utils
|
|||||||
import Handler.Utils.Invitations
|
import Handler.Utils.Invitations
|
||||||
|
|
||||||
import Jobs.Queue
|
import Jobs.Queue
|
||||||
|
|
||||||
import qualified Data.Conduit.Combinators as C
|
import qualified Data.Conduit.Combinators as C
|
||||||
|
|
||||||
|
|
||||||
@ -29,7 +29,7 @@ postCExamNewR tid ssh csh = do
|
|||||||
formResult newExamResult $ \ExamForm{..} -> do
|
formResult newExamResult $ \ExamForm{..} -> do
|
||||||
insertRes <- runDBJobs $ do
|
insertRes <- runDBJobs $ do
|
||||||
now <- liftIO getCurrentTime
|
now <- liftIO getCurrentTime
|
||||||
|
|
||||||
insertRes <- insertUnique Exam
|
insertRes <- insertUnique Exam
|
||||||
{ examName = efName
|
{ examName = efName
|
||||||
, examCourse = cid
|
, examCourse = cid
|
||||||
@ -90,7 +90,7 @@ postCExamNewR tid ssh csh = do
|
|||||||
when didRecord $
|
when didRecord $
|
||||||
audit $ TransactionExamResultEdit examid courseParticipantUser
|
audit $ TransactionExamResultEdit examid courseParticipantUser
|
||||||
runConduit $ selectSource [ CourseParticipantCourse ==. cid, CourseParticipantState ==. CourseParticipantInactive True ] [] .| C.mapM_ recordNoShow
|
runConduit $ selectSource [ CourseParticipantCourse ==. cid, CourseParticipantState ==. CourseParticipantInactive True ] [] .| C.mapM_ recordNoShow
|
||||||
|
|
||||||
return insertRes
|
return insertRes
|
||||||
case insertRes of
|
case insertRes of
|
||||||
Nothing -> addMessageI Error $ MsgExamNameTaken efName
|
Nothing -> addMessageI Error $ MsgExamNameTaken efName
|
||||||
|
|||||||
@ -21,7 +21,7 @@ data ButtonExamRegister = BtnExamRegisterOccurrence
|
|||||||
instance Universe ButtonExamRegister
|
instance Universe ButtonExamRegister
|
||||||
instance Finite ButtonExamRegister
|
instance Finite ButtonExamRegister
|
||||||
nullaryPathPiece ''ButtonExamRegister $ camelToPathPiece' 2
|
nullaryPathPiece ''ButtonExamRegister $ camelToPathPiece' 2
|
||||||
|
|
||||||
instance Button UniWorX ButtonExamRegister where
|
instance Button UniWorX ButtonExamRegister where
|
||||||
btnClasses BtnExamRegisterOccurrence = [BCIsButton, BCPrimary]
|
btnClasses BtnExamRegisterOccurrence = [BCIsButton, BCPrimary]
|
||||||
btnClasses BtnExamSwitchOccurrence = [BCIsButton, BCPrimary]
|
btnClasses BtnExamSwitchOccurrence = [BCIsButton, BCPrimary]
|
||||||
@ -36,9 +36,9 @@ instance Button UniWorX ButtonExamRegister where
|
|||||||
|
|
||||||
postERegisterR :: TermId -> SchoolId -> CourseShorthand -> ExamName -> Handler Html
|
postERegisterR :: TermId -> SchoolId -> CourseShorthand -> ExamName -> Handler Html
|
||||||
postERegisterR tid ssh csh examn = do
|
postERegisterR tid ssh csh examn = do
|
||||||
Entity uid User{..} <- requireAuth
|
uid <- requireAuthId
|
||||||
|
|
||||||
Entity eId Exam{..} <- runDB $ fetchExam tid ssh csh examn
|
Entity eId Exam{} <- runDB $ fetchExam tid ssh csh examn
|
||||||
|
|
||||||
((btnResult, _), _) <- runFormPost $ buttonForm' [BtnExamRegister, BtnExamDeregister]
|
((btnResult, _), _) <- runFormPost $ buttonForm' [BtnExamRegister, BtnExamDeregister]
|
||||||
|
|
||||||
@ -63,14 +63,14 @@ postERegisterR tid ssh csh examn = do
|
|||||||
|
|
||||||
postERegisterOccR :: TermId -> SchoolId -> CourseShorthand -> ExamName -> ExamOccurrenceName -> Handler Html
|
postERegisterOccR :: TermId -> SchoolId -> CourseShorthand -> ExamName -> ExamOccurrenceName -> Handler Html
|
||||||
postERegisterOccR tid ssh csh examn occn = do
|
postERegisterOccR tid ssh csh examn occn = do
|
||||||
Entity uid User{..} <- requireAuth
|
uid <- requireAuthId
|
||||||
(Entity eId Exam{..}, Entity occId ExamOccurrence{..}) <- runDB $ do
|
(eId, occId) <- runDB $ do
|
||||||
eexam@(Entity eId _) <- fetchExam tid ssh csh examn
|
Entity eId _ <- fetchExam tid ssh csh examn
|
||||||
occ <- getBy404 $ UniqueExamOccurrence eId occn
|
occ <- getKeyBy404 $ UniqueExamOccurrence eId occn
|
||||||
return (eexam, occ)
|
return (eId, occ)
|
||||||
|
|
||||||
((btnResult, _), _) <- runFormPost buttonForm
|
((btnResult, _), _) <- runFormPost buttonForm
|
||||||
|
|
||||||
formResult btnResult $ \case
|
formResult btnResult $ \case
|
||||||
BtnExamDeregister -> do
|
BtnExamDeregister -> do
|
||||||
runDB $ do
|
runDB $ do
|
||||||
@ -89,4 +89,4 @@ postERegisterOccR tid ssh csh examn occn = do
|
|||||||
_other -> error "Unexpected due to definition of buttonForm'"
|
_other -> error "Unexpected due to definition of buttonForm'"
|
||||||
|
|
||||||
redirect $ CExamR tid ssh csh examn EShowR
|
redirect $ CExamR tid ssh csh examn EShowR
|
||||||
|
|
||||||
|
|||||||
@ -16,13 +16,13 @@ import Handler.Utils.Invitations
|
|||||||
import qualified Data.Set as Set
|
import qualified Data.Set as Set
|
||||||
|
|
||||||
import Text.Hamlet (ihamlet)
|
import Text.Hamlet (ihamlet)
|
||||||
|
|
||||||
import Data.Aeson hiding (Result(..))
|
import Data.Aeson hiding (Result(..))
|
||||||
|
|
||||||
import Jobs.Queue
|
import Jobs.Queue
|
||||||
|
|
||||||
import qualified Data.HashSet as HashSet
|
import qualified Data.HashSet as HashSet
|
||||||
|
|
||||||
|
|
||||||
instance IsInvitableJunction ExamRegistration where
|
instance IsInvitableJunction ExamRegistration where
|
||||||
type InvitationFor ExamRegistration = Exam
|
type InvitationFor ExamRegistration = Exam
|
||||||
@ -98,7 +98,7 @@ examRegistrationInvitationConfig = InvitationConfig{..}
|
|||||||
(False, True ) -> do
|
(False, True ) -> do
|
||||||
fieldRes <- wreq (studyFeaturesFieldFor Nothing False [] $ Just uid) (fslI MsgCourseStudyFeature) Nothing
|
fieldRes <- wreq (studyFeaturesFieldFor Nothing False [] $ Just uid) (fslI MsgCourseStudyFeature) Nothing
|
||||||
return $ (JunctionExamRegistration invDBExamRegistrationOccurrence now, ) . Just <$> fieldRes
|
return $ (JunctionExamRegistration invDBExamRegistrationOccurrence now, ) . Just <$> fieldRes
|
||||||
(True , _ ) -> return $ pure (JunctionExamRegistration invDBExamRegistrationOccurrence now, Nothing)
|
(True , _ ) -> return $ pure (JunctionExamRegistration invDBExamRegistrationOccurrence now, Nothing)
|
||||||
invitationInsertHook _ (Entity eid Exam{..}) _ ExamRegistration{..} mField act = do
|
invitationInsertHook _ (Entity eid Exam{..}) _ ExamRegistration{..} mField act = do
|
||||||
whenIsJust mField $ \cpField -> do
|
whenIsJust mField $ \cpField -> do
|
||||||
void $ upsert
|
void $ upsert
|
||||||
@ -110,7 +110,7 @@ examRegistrationInvitationConfig = InvitationConfig{..}
|
|||||||
]
|
]
|
||||||
queueDBJob . JobQueueNotification $ NotificationCourseRegistered examRegistrationUser examCourse
|
queueDBJob . JobQueueNotification $ NotificationCourseRegistered examRegistrationUser examCourse
|
||||||
audit $ TransactionCourseParticipantEdit examCourse examRegistrationUser
|
audit $ TransactionCourseParticipantEdit examCourse examRegistrationUser
|
||||||
|
|
||||||
let doAudit = audit $ TransactionExamRegister eid examRegistrationUser
|
let doAudit = audit $ TransactionExamRegister eid examRegistrationUser
|
||||||
act <* doAudit
|
act <* doAudit
|
||||||
invitationSuccessMsg (Entity _ Exam{..}) _ = return . SomeMessage $ MsgExamRegistrationInvitationAccepted examName
|
invitationSuccessMsg (Entity _ Exam{..}) _ = return . SomeMessage $ MsgExamRegistrationInvitationAccepted examName
|
||||||
|
|||||||
@ -96,9 +96,9 @@ getEShowR tid ssh csh examn = do
|
|||||||
|
|
||||||
sumRegisteredCount = sumOf (folded . _3) occurrences
|
sumRegisteredCount = sumOf (folded . _3) occurrences
|
||||||
|
|
||||||
noBonus = fromMaybe False $ do
|
noBonus = (Just True ==) $ do
|
||||||
guardM $ bonusOnlyPassed <$> examBonusRule
|
guardM $ bonusOnlyPassed <$> examBonusRule
|
||||||
return . fromMaybe True $ result ^? _Just . _entityVal . _examResultResult . _examResult . to (either id $ view passingGrade) . _Wrapped . to not
|
return $ Just False /= result ^? _Just . _entityVal . _examResultResult . _examResult . to (either id $ view passingGrade) . _Wrapped . to not
|
||||||
|
|
||||||
sumPoints = fmap getSum . mconcat $ catMaybes
|
sumPoints = fmap getSum . mconcat $ catMaybes
|
||||||
[ Just $ foldMap (fmap Sum . examPartResultResult . entityVal) results
|
[ Just $ foldMap (fmap Sum . examPartResultResult . entityVal) results
|
||||||
@ -187,5 +187,5 @@ getEShowR tid ssh csh examn = do
|
|||||||
examBonusW bonusRule = $(widgetFile "widgets/bonusRule")
|
examBonusW bonusRule = $(widgetFile "widgets/bonusRule")
|
||||||
|
|
||||||
occurrenceMapping :: ExamOccurrenceName -> Maybe Widget
|
occurrenceMapping :: ExamOccurrenceName -> Maybe Widget
|
||||||
occurrenceMapping occName = examOccurrenceMappingDescriptionWidget <$> fmap examOccurrenceMappingRule examExamOccurrenceMapping <*> (fmap examOccurrenceMappingMapping examExamOccurrenceMapping >>= Map.lookup occName)
|
occurrenceMapping occName = examOccurrenceMappingDescriptionWidget <$> fmap examOccurrenceMappingRule examExamOccurrenceMapping <*> (examExamOccurrenceMapping >>= Map.lookup occName . examOccurrenceMappingMapping)
|
||||||
$(widgetFile "exam-show")
|
$(widgetFile "exam-show")
|
||||||
|
|||||||
@ -88,7 +88,7 @@ queryExamOccurrence = $(sqlLOJproj 6 2)
|
|||||||
|
|
||||||
queryCourseParticipant :: ExamUserTableExpr -> E.SqlExpr (Maybe (Entity CourseParticipant))
|
queryCourseParticipant :: ExamUserTableExpr -> E.SqlExpr (Maybe (Entity CourseParticipant))
|
||||||
queryCourseParticipant = $(sqlLOJproj 2 1) . $(sqlLOJproj 6 3)
|
queryCourseParticipant = $(sqlLOJproj 2 1) . $(sqlLOJproj 6 3)
|
||||||
|
|
||||||
queryStudyFeatures :: ExamUserTableExpr -> E.SqlExpr (Maybe (Entity StudyFeatures))
|
queryStudyFeatures :: ExamUserTableExpr -> E.SqlExpr (Maybe (Entity StudyFeatures))
|
||||||
queryStudyFeatures = $(sqlIJproj 3 1) . $(sqlLOJproj 2 2) . $(sqlLOJproj 6 3)
|
queryStudyFeatures = $(sqlIJproj 3 1) . $(sqlLOJproj 2 2) . $(sqlLOJproj 6 3)
|
||||||
|
|
||||||
@ -184,7 +184,7 @@ csvExamPartHeader = prism' toHeader fromHeader
|
|||||||
review _ExamPartNumber . CI.mk <$> stripPrefix partPrefix tHdr
|
review _ExamPartNumber . CI.mk <$> stripPrefix partPrefix tHdr
|
||||||
|
|
||||||
partPrefix = "part-"
|
partPrefix = "part-"
|
||||||
|
|
||||||
|
|
||||||
data ExamUserTableCsv = ExamUserTableCsv
|
data ExamUserTableCsv = ExamUserTableCsv
|
||||||
{ csvEUserSurname :: Maybe Text
|
{ csvEUserSurname :: Maybe Text
|
||||||
@ -498,7 +498,7 @@ postEUsersR tid ssh csh examn = do
|
|||||||
[ (epId, (examPart, mbRes))
|
[ (epId, (examPart, mbRes))
|
||||||
| (Entity epId examPart, mbRes) <- rawResults
|
| (Entity epId examPart, mbRes) <- rawResults
|
||||||
]
|
]
|
||||||
|
|
||||||
dbtColonnade = mconcat $ catMaybes
|
dbtColonnade = mconcat $ catMaybes
|
||||||
[ pure $ dbSelect (_2 . applying _2) _1 $ return . view (resultExamRegistration . _entityKey)
|
[ pure $ dbSelect (_2 . applying _2) _1 $ return . view (resultExamRegistration . _entityKey)
|
||||||
, pure $ colUserNameLink (CourseR tid ssh csh . CUserR)
|
, pure $ colUserNameLink (CourseR tid ssh csh . CUserR)
|
||||||
@ -507,7 +507,7 @@ postEUsersR tid ssh csh examn = do
|
|||||||
, pure $ colDegreeShort resultStudyDegree
|
, pure $ colDegreeShort resultStudyDegree
|
||||||
, pure $ colFeaturesSemester resultStudyFeatures
|
, pure $ colFeaturesSemester resultStudyFeatures
|
||||||
, pure $ sortable (Just "occurrence") (i18nCell MsgExamOccurrence) $ maybe mempty (anchorCell' (\n -> CExamR tid ssh csh examn EShowR :#: [st|exam-occurrence__#{n}|]) id . examOccurrenceName . entityVal) . view _userTableOccurrence
|
, pure $ sortable (Just "occurrence") (i18nCell MsgExamOccurrence) $ maybe mempty (anchorCell' (\n -> CExamR tid ssh csh examn EShowR :#: [st|exam-occurrence__#{n}|]) id . examOccurrenceName . entityVal) . view _userTableOccurrence
|
||||||
, guardOn showPasses $ sortable Nothing (i18nCell MsgAchievedPasses) $ \(view $ resultUser . _entityKey -> uid) ->
|
, guardOn showPasses $ sortable Nothing (i18nCell MsgAchievedPasses) $ \(view $ resultUser . _entityKey -> uid) ->
|
||||||
let SheetGradeSummary{achievedPasses} = examBonusAchieved uid bonus
|
let SheetGradeSummary{achievedPasses} = examBonusAchieved uid bonus
|
||||||
SheetGradeSummary{numSheetsPasses} = examBonusPossible uid bonus
|
SheetGradeSummary{numSheetsPasses} = examBonusPossible uid bonus
|
||||||
in propCell (getSum achievedPasses) (getSum numSheetsPasses)
|
in propCell (getSum achievedPasses) (getSum numSheetsPasses)
|
||||||
@ -516,7 +516,7 @@ postEUsersR tid ssh csh examn = do
|
|||||||
SheetGradeSummary{sumSheetsPoints} = examBonusPossible uid bonus
|
SheetGradeSummary{sumSheetsPoints} = examBonusPossible uid bonus
|
||||||
in propCell (getSum achievedPoints) (getSum sumSheetsPoints)
|
in propCell (getSum achievedPoints) (getSum sumSheetsPoints)
|
||||||
, guardOn doBonus $ sortable (Just "bonus") (i18nCell MsgExamBonusAchieved) . automaticCell $ resultExamBonus . _entityVal . _examBonusBonus . to Right <> resultAutomaticExamBonus' . to Left
|
, guardOn doBonus $ sortable (Just "bonus") (i18nCell MsgExamBonusAchieved) . automaticCell $ resultExamBonus . _entityVal . _examBonusBonus . to Right <> resultAutomaticExamBonus' . to Left
|
||||||
, pure $ mconcat
|
, pure $ mconcat
|
||||||
[ sortable (Just $ fromText [st|part-#{toPathPiece examPartNumber}|]) (i18nCell $ MsgExamPartNumbered examPartNumber) $ maybe mempty i18nCell . preview (resultExamPartResult epId . _Just . _entityVal . _examPartResultResult)
|
[ sortable (Just $ fromText [st|part-#{toPathPiece examPartNumber}|]) (i18nCell $ MsgExamPartNumbered examPartNumber) $ maybe mempty i18nCell . preview (resultExamPartResult epId . _Just . _entityVal . _examPartResultResult)
|
||||||
| Entity epId ExamPart{..} <- sortOn (examPartNumber . entityVal) examParts
|
| Entity epId ExamPart{..} <- sortOn (examPartNumber . entityVal) examParts
|
||||||
]
|
]
|
||||||
@ -597,7 +597,7 @@ postEUsersR tid ssh csh examn = do
|
|||||||
tell =<< optionsF [ ExamUserDeregister, ExamUserAssignOccurrence ]
|
tell =<< optionsF [ ExamUserDeregister, ExamUserAssignOccurrence ]
|
||||||
when (is _Just examGradingRule) $
|
when (is _Just examGradingRule) $
|
||||||
tell =<< optionsF [ ExamUserAcceptComputedResult, ExamUserResetToComputedResult ]
|
tell =<< optionsF [ ExamUserAcceptComputedResult, ExamUserResetToComputedResult ]
|
||||||
when (not $ null examParts) $
|
unless (null examParts) $
|
||||||
tell =<< optionsF [ ExamUserSetPartResult ]
|
tell =<< optionsF [ ExamUserSetPartResult ]
|
||||||
when doBonus $
|
when doBonus $
|
||||||
tell =<< optionsF [ ExamUserSetBonus ]
|
tell =<< optionsF [ ExamUserSetBonus ]
|
||||||
@ -651,7 +651,7 @@ postEUsersR tid ssh csh examn = do
|
|||||||
(isPart, uid) <- lift $ guessUser' dbCsvNew
|
(isPart, uid) <- lift $ guessUser' dbCsvNew
|
||||||
if
|
if
|
||||||
| isPart -> do
|
| isPart -> do
|
||||||
yieldM $ ExamUserCsvRegisterData <$> pure uid <*> lookupOccurrence dbCsvNew
|
yieldM $ ExamUserCsvRegisterData uid <$> lookupOccurrence dbCsvNew
|
||||||
newFeatures <- lift $ lookupStudyFeatures dbCsvNew
|
newFeatures <- lift $ lookupStudyFeatures dbCsvNew
|
||||||
Entity cpId CourseParticipant{ courseParticipantField = oldFeatures } <- lift . getJustBy $ UniqueParticipant uid examCourse
|
Entity cpId CourseParticipant{ courseParticipantField = oldFeatures } <- lift . getJustBy $ UniqueParticipant uid examCourse
|
||||||
when (newFeatures /= oldFeatures) $
|
when (newFeatures /= oldFeatures) $
|
||||||
@ -662,10 +662,10 @@ postEUsersR tid ssh csh examn = do
|
|||||||
iforMOf_ (ifolded <. _Just) (csvEUserExamPartResults dbCsvNew) $ \epNumber epRes ->
|
iforMOf_ (ifolded <. _Just) (csvEUserExamPartResults dbCsvNew) $ \epNumber epRes ->
|
||||||
when (epNumber `elem` examPartNumbers) $
|
when (epNumber `elem` examPartNumbers) $
|
||||||
yield $ ExamUserCsvSetPartResultData uid epNumber (Just epRes)
|
yield $ ExamUserCsvSetPartResultData uid epNumber (Just epRes)
|
||||||
|
|
||||||
when (doBonus && is _Just (join $ csvEUserBonus dbCsvNew)) $
|
when (doBonus && is _Just (join $ csvEUserBonus dbCsvNew)) $
|
||||||
yield . ExamUserCsvSetBonusData False uid . join $ csvEUserBonus dbCsvNew
|
yield . ExamUserCsvSetBonusData False uid . join $ csvEUserBonus dbCsvNew
|
||||||
|
|
||||||
whenIsJust (csvEUserExamResult dbCsvNew) $ \res -> do
|
whenIsJust (csvEUserExamResult dbCsvNew) $ \res -> do
|
||||||
yield . ExamUserCsvSetResultData False uid $ csvEUserExamResult dbCsvNew
|
yield . ExamUserCsvSetResultData False uid $ csvEUserExamResult dbCsvNew
|
||||||
guardResultKind res
|
guardResultKind res
|
||||||
@ -693,7 +693,7 @@ postEUsersR tid ssh csh examn = do
|
|||||||
|
|
||||||
let newResults :: Maybe (Map ExamPartNumber ExamResultPoints)
|
let newResults :: Maybe (Map ExamPartNumber ExamResultPoints)
|
||||||
newResults = sequence (csvEUserExamPartResults dbCsvNew)
|
newResults = sequence (csvEUserExamPartResults dbCsvNew)
|
||||||
<|> sequence (toMapOf (resultExamParts .> ito (over _1 $ examPartNumber) <. to (fmap $ examPartResultResult . entityVal)) dbCsvOld)
|
<|> sequence (toMapOf (resultExamParts .> ito (over _1 examPartNumber) <. to (fmap $ examPartResultResult . entityVal)) dbCsvOld)
|
||||||
|
|
||||||
newBonus, oldBonus :: Maybe Points
|
newBonus, oldBonus :: Maybe Points
|
||||||
newBonus = join (csvEUserBonus dbCsvNew)
|
newBonus = join (csvEUserBonus dbCsvNew)
|
||||||
@ -702,7 +702,7 @@ postEUsersR tid ssh csh examn = do
|
|||||||
newResult, oldResult :: Maybe ExamResultPassedGrade
|
newResult, oldResult :: Maybe ExamResultPassedGrade
|
||||||
newResult = fmap (fmap $ bool Right (Left . view passingGrade) $ is _ExamGradingGrades examGradingMode) . examGrade examVal (newBonus <|> oldBonus) =<< newResults
|
newResult = fmap (fmap $ bool Right (Left . view passingGrade) $ is _ExamGradingGrades examGradingMode) . examGrade examVal (newBonus <|> oldBonus) =<< newResults
|
||||||
oldResult = dbCsvOld ^? (resultExamResult . _entityVal . _examResultResult <> resultAutomaticExamResult')
|
oldResult = dbCsvOld ^? (resultExamResult . _entityVal . _examResultResult <> resultAutomaticExamResult')
|
||||||
|
|
||||||
when doBonus $
|
when doBonus $
|
||||||
case newBonus of
|
case newBonus of
|
||||||
_ | newBonus == oldBonus
|
_ | newBonus == oldBonus
|
||||||
@ -715,7 +715,7 @@ postEUsersR tid ssh csh examn = do
|
|||||||
-> yield $ ExamUserCsvSetBonusData False uid newBonus
|
-> yield $ ExamUserCsvSetBonusData False uid newBonus
|
||||||
Just _
|
Just _
|
||||||
-> yield $ ExamUserCsvSetBonusData True uid newBonus
|
-> yield $ ExamUserCsvSetBonusData True uid newBonus
|
||||||
|
|
||||||
case newResult of
|
case newResult of
|
||||||
_ | csvEUserExamResult dbCsvNew == oldResult
|
_ | csvEUserExamResult dbCsvNew == oldResult
|
||||||
-> return ()
|
-> return ()
|
||||||
@ -964,15 +964,15 @@ postEUsersR tid ssh csh examn = do
|
|||||||
| is (_ExamAttended . _Left) res -> ExamGradingPass
|
| is (_ExamAttended . _Left) res -> ExamGradingPass
|
||||||
| otherwise -> ExamGradingGrades
|
| otherwise -> ExamGradingGrades
|
||||||
| otherwise = return ()
|
| otherwise = return ()
|
||||||
|
|
||||||
registeredUserName :: Map (E.Value ExamRegistrationId) ExamUserTableData -> ExamRegistrationId -> Widget
|
registeredUserName :: Map (E.Value ExamRegistrationId) ExamUserTableData -> ExamRegistrationId -> Widget
|
||||||
registeredUserName existing (E.Value -> registration) = nameWidget userDisplayName userSurname
|
registeredUserName existing (E.Value -> registration) = nameWidget userDisplayName userSurname
|
||||||
where
|
where
|
||||||
Entity _ User{..} = view resultUser $ existing ! registration
|
Entity _ User{..} = view resultUser $ existing ! registration
|
||||||
|
|
||||||
guessUser' :: ExamUserTableCsv -> DB (Bool, UserId)
|
guessUser' :: ExamUserTableCsv -> DB (Bool, UserId)
|
||||||
guessUser' ExamUserTableCsv{..} = do
|
guessUser' ExamUserTableCsv{..} = do
|
||||||
let criteria = Set.fromList $ catMaybes
|
let criteria = Set.fromList $ catMaybes
|
||||||
[ GuessUserMatrikelnummer <$> csvEUserMatriculation
|
[ GuessUserMatrikelnummer <$> csvEUserMatriculation
|
||||||
, GuessUserDisplayName <$> csvEUserName
|
, GuessUserDisplayName <$> csvEUserName
|
||||||
, GuessUserSurname <$> csvEUserSurname
|
, GuessUserSurname <$> csvEUserSurname
|
||||||
@ -1088,7 +1088,7 @@ postEUsersR tid ssh csh examn = do
|
|||||||
audit $ TransactionExamBonusEdit eId uid
|
audit $ TransactionExamBonusEdit eId uid
|
||||||
| otherwise
|
| otherwise
|
||||||
-> return ()
|
-> return ()
|
||||||
|
|
||||||
insert_ ExamResult
|
insert_ ExamResult
|
||||||
{ examResultExam = eId
|
{ examResultExam = eId
|
||||||
, examResultUser = uid
|
, examResultUser = uid
|
||||||
|
|||||||
@ -28,7 +28,7 @@ getCExamOfficeR = postCExamOfficeR
|
|||||||
postCExamOfficeR tid ssh csh = do
|
postCExamOfficeR tid ssh csh = do
|
||||||
uid <- requireAuthId
|
uid <- requireAuthId
|
||||||
isModal <- hasCustomHeader HeaderIsModal
|
isModal <- hasCustomHeader HeaderIsModal
|
||||||
|
|
||||||
(cid, optOuts, hasForced) <- runDB $ do
|
(cid, optOuts, hasForced) <- runDB $ do
|
||||||
cid <- getKeyBy404 (TermSchoolCourseShort tid ssh csh)
|
cid <- getKeyBy404 (TermSchoolCourseShort tid ssh csh)
|
||||||
optOuts <- selectList [ CourseUserExamOfficeOptOutCourse ==. cid, CourseUserExamOfficeOptOutUser ==. uid ] []
|
optOuts <- selectList [ CourseUserExamOfficeOptOutCourse ==. cid, CourseUserExamOfficeOptOutUser ==. uid ] []
|
||||||
@ -65,7 +65,7 @@ postCExamOfficeR tid ssh csh = do
|
|||||||
setTitleI MsgMenuCourseExamOffice
|
setTitleI MsgMenuCourseExamOffice
|
||||||
|
|
||||||
let explanation = $(i18nWidgetFile "course-exam-office-explanation")
|
let explanation = $(i18nWidgetFile "course-exam-office-explanation")
|
||||||
|
|
||||||
[whamlet|
|
[whamlet|
|
||||||
$newline never
|
$newline never
|
||||||
<section>
|
<section>
|
||||||
|
|||||||
@ -34,7 +34,7 @@ embedRenderMessage ''UniWorX ''ButtonCloseExam id
|
|||||||
instance Button UniWorX ButtonCloseExam where
|
instance Button UniWorX ButtonCloseExam where
|
||||||
btnClasses BtnCloseExam = [BCIsButton]
|
btnClasses BtnCloseExam = [BCIsButton]
|
||||||
|
|
||||||
|
|
||||||
examCloseWidget :: SomeRoute UniWorX -> ExamId -> Handler Widget
|
examCloseWidget :: SomeRoute UniWorX -> ExamId -> Handler Widget
|
||||||
examCloseWidget dest eId = do
|
examCloseWidget dest eId = do
|
||||||
Exam{..} <- runDB $ get404 eId
|
Exam{..} <- runDB $ get404 eId
|
||||||
@ -47,7 +47,7 @@ examCloseWidget dest eId = do
|
|||||||
|
|
||||||
unless (is _Nothing examClosed) $
|
unless (is _Nothing examClosed) $
|
||||||
invalidArgs ["Exam is already closed"]
|
invalidArgs ["Exam is already closed"]
|
||||||
|
|
||||||
runDB $ update eId [ ExamClosed =. Just now ]
|
runDB $ update eId [ ExamClosed =. Just now ]
|
||||||
addMessageI Success MsgExamDidClose
|
addMessageI Success MsgExamDidClose
|
||||||
redirect dest
|
redirect dest
|
||||||
@ -189,7 +189,7 @@ newtype ExamUserCsvExportData = ExamUserCsvExportData
|
|||||||
{ csvEUserMarkSynchronised :: Bool
|
{ csvEUserMarkSynchronised :: Bool
|
||||||
} deriving (Eq, Ord, Read, Show, Generic, Typeable)
|
} deriving (Eq, Ord, Read, Show, Generic, Typeable)
|
||||||
|
|
||||||
|
|
||||||
-- | View a list of all users' grades that the current user has access to
|
-- | View a list of all users' grades that the current user has access to
|
||||||
getEGradesR, postEGradesR :: TermId -> SchoolId -> CourseShorthand -> ExamName -> Handler Html
|
getEGradesR, postEGradesR :: TermId -> SchoolId -> CourseShorthand -> ExamName -> Handler Html
|
||||||
getEGradesR = postEGradesR
|
getEGradesR = postEGradesR
|
||||||
@ -271,7 +271,7 @@ postEGradesR tid ssh csh examn = do
|
|||||||
|
|
||||||
E.where_ $ examResult E.^. ExamResultExam E.==. E.val eid
|
E.where_ $ examResult E.^. ExamResultExam E.==. E.val eid
|
||||||
|
|
||||||
unless isLecturer $
|
unless isLecturer $
|
||||||
E.where_ $ Exam.examOfficeExamResultAuth (E.val uid) examResult
|
E.where_ $ Exam.examOfficeExamResultAuth (E.val uid) examResult
|
||||||
|
|
||||||
return (examResult, user, occurrence, studyFeatures, studyDegree, studyField, examRegistration, isSynced)
|
return (examResult, user, occurrence, studyFeatures, studyDegree, studyField, examRegistration, isSynced)
|
||||||
@ -314,9 +314,9 @@ postEGradesR tid ssh csh examn = do
|
|||||||
syncs' = [ Right sync | sync@(_, _, t, _) <- syncs, t > lastChange]
|
syncs' = [ Right sync | sync@(_, _, t, _) <- syncs, t > lastChange]
|
||||||
++ [ Left lastChange ]
|
++ [ Left lastChange ]
|
||||||
++ [ Right sync | sync@(_, _, t, _) <- syncs, t <= lastChange]
|
++ [ Right sync | sync@(_, _, t, _) <- syncs, t <= lastChange]
|
||||||
|
|
||||||
syncIcon :: Widget
|
syncIcon :: Widget
|
||||||
syncIcon
|
syncIcon
|
||||||
| not isSynced
|
| not isSynced
|
||||||
, not hasSyncs
|
, not hasSyncs
|
||||||
= mempty
|
= mempty
|
||||||
@ -324,7 +324,7 @@ postEGradesR tid ssh csh examn = do
|
|||||||
= toWidget iconNotOK
|
= toWidget iconNotOK
|
||||||
| otherwise
|
| otherwise
|
||||||
= toWidget iconOK
|
= toWidget iconOK
|
||||||
|
|
||||||
syncsModal :: Widget
|
syncsModal :: Widget
|
||||||
syncsModal = $(widgetFile "exam-office/exam-result-synced")
|
syncsModal = $(widgetFile "exam-office/exam-result-synced")
|
||||||
lift $ bool id (flip modal $ Right syncsModal) hasSyncs syncIcon
|
lift $ bool id (flip modal $ Right syncsModal) hasSyncs syncIcon
|
||||||
|
|||||||
@ -30,7 +30,7 @@ queryExam = to $ $(E.sqlIJproj 2 1) . $(E.sqlFOJproj 2 1)
|
|||||||
|
|
||||||
queryCourse :: Getter ExamsTableExpr (E.SqlExpr (Maybe (Entity Course)))
|
queryCourse :: Getter ExamsTableExpr (E.SqlExpr (Maybe (Entity Course)))
|
||||||
queryCourse = to $ $(E.sqlIJproj 2 2) . $(E.sqlFOJproj 2 1)
|
queryCourse = to $ $(E.sqlIJproj 2 2) . $(E.sqlFOJproj 2 1)
|
||||||
|
|
||||||
queryExternalExam :: Getter ExamsTableExpr (E.SqlExpr (Maybe (Entity ExternalExam)))
|
queryExternalExam :: Getter ExamsTableExpr (E.SqlExpr (Maybe (Entity ExternalExam)))
|
||||||
queryExternalExam = to $(E.sqlFOJproj 2 2)
|
queryExternalExam = to $(E.sqlFOJproj 2 2)
|
||||||
|
|
||||||
@ -48,7 +48,7 @@ querySynchronised office = to . runReader $ do
|
|||||||
E.where_ $ ExternalExam.examOfficeExternalExamResultAuth office externalExamResult
|
E.where_ $ ExternalExam.examOfficeExternalExamResultAuth office externalExamResult
|
||||||
E.where_ $ ExternalExam.resultIsSynced office externalExamResult
|
E.where_ $ ExternalExam.resultIsSynced office externalExamResult
|
||||||
return $ E.maybe (E.val 0) examSynchronised (exam' E.?. ExamId) E.+. E.maybe (E.val 0) externalExamSynchronised (externalExam' E.?. ExternalExamId)
|
return $ E.maybe (E.val 0) examSynchronised (exam' E.?. ExamId) E.+. E.maybe (E.val 0) externalExamSynchronised (externalExam' E.?. ExternalExamId)
|
||||||
|
|
||||||
queryResults :: E.SqlExpr (E.Value UserId) -> Getter ExamsTableExpr (E.SqlExpr (E.Value Natural))
|
queryResults :: E.SqlExpr (E.Value UserId) -> Getter ExamsTableExpr (E.SqlExpr (E.Value Natural))
|
||||||
queryResults office = to . runReader $ do
|
queryResults office = to . runReader $ do
|
||||||
exam' <- view queryExam
|
exam' <- view queryExam
|
||||||
@ -75,7 +75,7 @@ queryIsSynced now office = to . runReader $ do
|
|||||||
E.where_ $ externalExamResult E.^. ExternalExamResultExam E.==. externalExamId
|
E.where_ $ externalExamResult E.^. ExternalExamResultExam E.==. externalExamId
|
||||||
E.where_ $ ExternalExam.examOfficeExternalExamResultAuth office externalExamResult
|
E.where_ $ ExternalExam.examOfficeExternalExamResultAuth office externalExamResult
|
||||||
E.where_ . E.not_ $ ExternalExam.resultIsSynced office externalExamResult
|
E.where_ . E.not_ $ ExternalExam.resultIsSynced office externalExamResult
|
||||||
open examClosed' = E.maybe E.true (E.>. E.val now) $ examClosed'
|
open examClosed' = E.maybe E.true (E.>. E.val now) examClosed'
|
||||||
return $ E.maybe E.false examSynchronised (exam' E.?. ExamId) E.||. E.maybe E.false open (exam' E.?. ExamClosed) E.||. E.maybe E.false externalExamSynchronised (externalExam' E.?. ExternalExamId)
|
return $ E.maybe E.false examSynchronised (exam' E.?. ExamId) E.||. E.maybe E.false open (exam' E.?. ExamClosed) E.||. E.maybe E.false externalExamSynchronised (externalExam' E.?. ExternalExamId)
|
||||||
|
|
||||||
|
|
||||||
@ -95,7 +95,7 @@ resultResults = _dbrOutput . _3
|
|||||||
resultIsSynced :: Getter ExamsTableData Bool
|
resultIsSynced :: Getter ExamsTableData Bool
|
||||||
resultIsSynced = to $ (>=) <$> view resultSynchronised <*> view resultResults
|
resultIsSynced = to $ (>=) <$> view resultSynchronised <*> view resultResults
|
||||||
|
|
||||||
|
|
||||||
-- | List of all exams where the current user may (in her function as
|
-- | List of all exams where the current user may (in her function as
|
||||||
-- exam-office) access users grades
|
-- exam-office) access users grades
|
||||||
getEOExamsR :: Handler Html
|
getEOExamsR :: Handler Html
|
||||||
@ -106,15 +106,15 @@ getEOExamsR = do
|
|||||||
examsTable <- runDB $ do
|
examsTable <- runDB $ do
|
||||||
let
|
let
|
||||||
examLink :: Course -> Exam -> SomeRoute UniWorX
|
examLink :: Course -> Exam -> SomeRoute UniWorX
|
||||||
examLink Course{..} Exam{..}
|
examLink Course{..} Exam{..}
|
||||||
= SomeRoute $ CExamR courseTerm courseSchool courseShorthand examName EGradesR
|
= SomeRoute $ CExamR courseTerm courseSchool courseShorthand examName EGradesR
|
||||||
|
|
||||||
courseLink :: Course -> SomeRoute UniWorX
|
courseLink :: Course -> SomeRoute UniWorX
|
||||||
courseLink Course{..}
|
courseLink Course{..}
|
||||||
= SomeRoute $ CourseR courseTerm courseSchool courseShorthand CShowR
|
= SomeRoute $ CourseR courseTerm courseSchool courseShorthand CShowR
|
||||||
|
|
||||||
externalExamLink :: ExternalExam -> SomeRoute UniWorX
|
externalExamLink :: ExternalExam -> SomeRoute UniWorX
|
||||||
externalExamLink ExternalExam{..}
|
externalExamLink ExternalExam{..}
|
||||||
= SomeRoute $ EExamR externalExamTerm externalExamSchool externalExamCourseName externalExamExamName EEGradesR
|
= SomeRoute $ EExamR externalExamTerm externalExamSchool externalExamCourseName externalExamExamName EEGradesR
|
||||||
|
|
||||||
querySynchronised' = querySynchronised $ E.val uid
|
querySynchronised' = querySynchronised $ E.val uid
|
||||||
@ -150,11 +150,9 @@ getEOExamsR = do
|
|||||||
|
|
||||||
case (exam, course, externalExam) of
|
case (exam, course, externalExam) of
|
||||||
(Just exam', Just course', Nothing) ->
|
(Just exam', Just course', Nothing) ->
|
||||||
(,,)
|
(Right (exam', course'),,) <$> view (_4 . _Value) <*> view (_5 . _Value)
|
||||||
<$> pure (Right (exam', course')) <*> view (_4 . _Value) <*> view (_5 . _Value)
|
|
||||||
(Nothing, Nothing, Just externalExam') ->
|
(Nothing, Nothing, Just externalExam') ->
|
||||||
(,,)
|
(Left externalExam',,) <$> view (_4 . _Value) <*> view (_5 . _Value)
|
||||||
<$> pure (Left externalExam') <*> view (_4 . _Value) <*> view (_5 . _Value)
|
|
||||||
_other -> return $ error "Got exam & externalExam in same result"
|
_other -> return $ error "Got exam & externalExam in same result"
|
||||||
|
|
||||||
|
|
||||||
@ -182,7 +180,7 @@ getEOExamsR = do
|
|||||||
& cellAttrs <>~ [ ("class", "heated")
|
& cellAttrs <>~ [ ("class", "heated")
|
||||||
, ("style", [st|--hotness: #{tshow (heat results synced)}|])
|
, ("style", [st|--hotness: #{tshow (heat results synced)}|])
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
dbtColonnade :: Colonnade Sortable _ _
|
dbtColonnade :: Colonnade Sortable _ _
|
||||||
dbtColonnade = mconcat
|
dbtColonnade = mconcat
|
||||||
@ -192,7 +190,7 @@ getEOExamsR = do
|
|||||||
)
|
)
|
||||||
$ emptyOpticColonnade (resultExam . _entityVal . _examName <> resultExternalExam . _entityVal . _externalExamExamName) colExamName
|
$ emptyOpticColonnade (resultExam . _entityVal . _examName <> resultExternalExam . _entityVal . _externalExamExamName) colExamName
|
||||||
, emptyOpticColonnade (resultExam . _entityVal . $(multifocusG 2) _examStart _examEnd) colExamTime
|
, emptyOpticColonnade (resultExam . _entityVal . $(multifocusG 2) _examStart _examEnd) colExamTime
|
||||||
, emptyOpticColonnade (resultExam . _entityVal . _examFinished) colExamFinishedOffice
|
, emptyOpticColonnade (resultExam . _entityVal . _examFinished) colExamFinishedOffice
|
||||||
, emptyOpticColonnade (resultExam . _entityVal . _examClosed) colExamClosed
|
, emptyOpticColonnade (resultExam . _entityVal . _examClosed) colExamClosed
|
||||||
, maybeAnchorColonnade (previews (resultCourse . _entityVal) courseLink)
|
, maybeAnchorColonnade (previews (resultCourse . _entityVal) courseLink)
|
||||||
$ emptyOpticColonnade (resultCourse . _entityVal . _courseName <> resultExternalExam . _entityVal . _externalExamCourseName) colCourseName
|
$ emptyOpticColonnade (resultCourse . _entityVal . _courseName <> resultExternalExam . _entityVal . _externalExamCourseName) colCourseName
|
||||||
|
|||||||
@ -7,7 +7,7 @@ import Import
|
|||||||
import Handler.Utils
|
import Handler.Utils
|
||||||
|
|
||||||
import Handler.Utils.ExternalExam.Users
|
import Handler.Utils.ExternalExam.Users
|
||||||
|
|
||||||
getEEGradesR, postEEGradesR :: TermId -> SchoolId -> CourseName -> ExamName -> Handler Html
|
getEEGradesR, postEEGradesR :: TermId -> SchoolId -> CourseName -> ExamName -> Handler Html
|
||||||
getEEGradesR = postEEGradesR
|
getEEGradesR = postEEGradesR
|
||||||
postEEGradesR tid ssh coursen examn = do
|
postEEGradesR tid ssh coursen examn = do
|
||||||
|
|||||||
@ -11,7 +11,7 @@ import qualified Database.Esqueleto as E
|
|||||||
import qualified Data.Set as Set
|
import qualified Data.Set as Set
|
||||||
import qualified Data.Map as Map
|
import qualified Data.Map as Map
|
||||||
|
|
||||||
|
|
||||||
data ExamOfficeFieldMode
|
data ExamOfficeFieldMode
|
||||||
= EOFNotSubscribed
|
= EOFNotSubscribed
|
||||||
| EOFSubscribed
|
| EOFSubscribed
|
||||||
@ -78,7 +78,7 @@ postEOFieldsR = do
|
|||||||
oldFields <- runDB $ do
|
oldFields <- runDB $ do
|
||||||
fields <- E.select . E.from $ \examOfficeField -> do
|
fields <- E.select . E.from $ \examOfficeField -> do
|
||||||
E.where_ $ examOfficeField E.^. ExamOfficeFieldOffice E.==. E.val uid
|
E.where_ $ examOfficeField E.^. ExamOfficeFieldOffice E.==. E.val uid
|
||||||
return $ (examOfficeField E.^. ExamOfficeFieldField, examOfficeField E.^. ExamOfficeFieldForced)
|
return (examOfficeField E.^. ExamOfficeFieldField, examOfficeField E.^. ExamOfficeFieldForced)
|
||||||
return $ toMapOf (folded .> ito (over _1 E.unValue . over _2 E.unValue)) fields
|
return $ toMapOf (folded .> ito (over _1 E.unValue . over _2 E.unValue)) fields
|
||||||
|
|
||||||
((fieldsRes, fieldsView), fieldsEnc) <- runFormPost . makeExamOfficeFieldsForm uid $ Just oldFields
|
((fieldsRes, fieldsView), fieldsEnc) <- runFormPost . makeExamOfficeFieldsForm uid $ Just oldFields
|
||||||
|
|||||||
@ -21,7 +21,7 @@ import qualified Data.Map as Map
|
|||||||
import Data.Map ((!), (!?))
|
import Data.Map ((!), (!?))
|
||||||
|
|
||||||
import qualified Data.HashSet as HashSet
|
import qualified Data.HashSet as HashSet
|
||||||
|
|
||||||
|
|
||||||
instance IsInvitableJunction ExamOfficeUser where
|
instance IsInvitableJunction ExamOfficeUser where
|
||||||
type InvitationFor ExamOfficeUser = User
|
type InvitationFor ExamOfficeUser = User
|
||||||
@ -84,11 +84,11 @@ examOfficeUserInvitationConfig = InvitationConfig{..}
|
|||||||
return $ SomeMessage MsgExamOfficeUserInvitationAccepted
|
return $ SomeMessage MsgExamOfficeUserInvitationAccepted
|
||||||
invitationUltDest _ _ = return $ SomeRoute NewsR
|
invitationUltDest _ _ = return $ SomeRoute NewsR
|
||||||
|
|
||||||
|
|
||||||
makeExamOfficeUsersForm :: Maybe (Set (Either UserEmail UserId)) -> Form (Set (Either UserEmail UserId))
|
makeExamOfficeUsersForm :: Maybe (Set (Either UserEmail UserId)) -> Form (Set (Either UserEmail UserId))
|
||||||
makeExamOfficeUsersForm template = renderWForm FormStandard $ do
|
makeExamOfficeUsersForm template = renderWForm FormStandard $ do
|
||||||
cRoute <- fromMaybe (error "makeExamOfficeUsersForm called from 404-handler") <$> getCurrentRoute
|
cRoute <- fromMaybe (error "makeExamOfficeUsersForm called from 404-handler") <$> getCurrentRoute
|
||||||
|
|
||||||
let
|
let
|
||||||
miAdd' :: (Text -> Text)
|
miAdd' :: (Text -> Text)
|
||||||
-> FieldView UniWorX
|
-> FieldView UniWorX
|
||||||
@ -132,7 +132,7 @@ makeExamOfficeUsersForm template = renderWForm FormStandard $ do
|
|||||||
return $ map Left invitations ++ map Right knownUsers'
|
return $ map Left invitations ++ map Right knownUsers'
|
||||||
|
|
||||||
fmap Set.fromList <$> massInputAccumW miAdd' miCell' miButtonAction' miLayout' miIdent' fSettings fRequired template'
|
fmap Set.fromList <$> massInputAccumW miAdd' miCell' miButtonAction' miLayout' miIdent' fSettings fRequired template'
|
||||||
|
|
||||||
|
|
||||||
-- | Manage the list of users this user (in her function as exam-office)
|
-- | Manage the list of users this user (in her function as exam-office)
|
||||||
-- has an interest in, i.e. that authorize her to view their grades
|
-- has an interest in, i.e. that authorize her to view their grades
|
||||||
|
|||||||
@ -39,7 +39,7 @@ postEEEditR tid ssh coursen examn = do
|
|||||||
, eefOfficeSchools = schools
|
, eefOfficeSchools = schools
|
||||||
, eefStaff = staff
|
, eefStaff = staff
|
||||||
}
|
}
|
||||||
|
|
||||||
((examResult, examWidget'), examEnctype) <- runFormPost . externalExamForm $ Just template
|
((examResult, examWidget'), examEnctype) <- runFormPost . externalExamForm $ Just template
|
||||||
|
|
||||||
formResult examResult $ \ExternalExamForm{..} -> do
|
formResult examResult $ \ExternalExamForm{..} -> do
|
||||||
@ -54,7 +54,7 @@ postEEEditR tid ssh coursen examn = do
|
|||||||
}
|
}
|
||||||
when (is _Nothing replaceRes) $ do
|
when (is _Nothing replaceRes) $ do
|
||||||
audit $ TransactionExternalExamEdit eeId
|
audit $ TransactionExternalExamEdit eeId
|
||||||
|
|
||||||
forM_ (eefStaff `setSymmDiff` staff) $ \change -> if
|
forM_ (eefStaff `setSymmDiff` staff) $ \change -> if
|
||||||
| change `Set.member` eefStaff -> case change of
|
| change `Set.member` eefStaff -> case change of
|
||||||
Left invEmail -> do
|
Left invEmail -> do
|
||||||
|
|||||||
@ -5,7 +5,7 @@ module Handler.ExternalExam.Form
|
|||||||
|
|
||||||
import Import
|
import Import
|
||||||
import Handler.Utils
|
import Handler.Utils
|
||||||
|
|
||||||
import Handler.ExternalExam.StaffInvite ()
|
import Handler.ExternalExam.StaffInvite ()
|
||||||
|
|
||||||
import qualified Data.Set as Set
|
import qualified Data.Set as Set
|
||||||
@ -104,7 +104,7 @@ externalExamForm template = validateForm validateExternalExam $ \html -> do
|
|||||||
validateExternalExam :: (MonadThrow m, MonadHandler m, HandlerSite m ~ UniWorX) => FormValidator ExternalExamForm m ()
|
validateExternalExam :: (MonadThrow m, MonadHandler m, HandlerSite m ~ UniWorX) => FormValidator ExternalExamForm m ()
|
||||||
validateExternalExam = do
|
validateExternalExam = do
|
||||||
State.modify $ \eeForm -> eeForm & over _eefOfficeSchools (Set.delete $ eeForm ^. _eefSchool)
|
State.modify $ \eeForm -> eeForm & over _eefOfficeSchools (Set.delete $ eeForm ^. _eefSchool)
|
||||||
|
|
||||||
ExternalExamForm{..} <- State.get
|
ExternalExamForm{..} <- State.get
|
||||||
|
|
||||||
isAdmin <- hasWriteAccessTo $ SchoolR eefSchool SchoolEditR
|
isAdmin <- hasWriteAccessTo $ SchoolR eefSchool SchoolEditR
|
||||||
|
|||||||
@ -3,7 +3,7 @@ module Handler.ExternalExam.List
|
|||||||
) where
|
) where
|
||||||
|
|
||||||
import Import
|
import Import
|
||||||
|
|
||||||
import Handler.Utils
|
import Handler.Utils
|
||||||
|
|
||||||
import qualified Database.Esqueleto as E
|
import qualified Database.Esqueleto as E
|
||||||
@ -24,7 +24,7 @@ getEExamListR = do
|
|||||||
|
|
||||||
queryEExam = $(E.sqlIJproj 2 1)
|
queryEExam = $(E.sqlIJproj 2 1)
|
||||||
querySchool = $(E.sqlIJproj 2 2)
|
querySchool = $(E.sqlIJproj 2 2)
|
||||||
|
|
||||||
dbtSQLQuery (eexam `E.InnerJoin` school) = do
|
dbtSQLQuery (eexam `E.InnerJoin` school) = do
|
||||||
E.on $ eexam E.^. ExternalExamSchool E.==. school E.^. SchoolId
|
E.on $ eexam E.^. ExternalExamSchool E.==. school E.^. SchoolId
|
||||||
let
|
let
|
||||||
|
|||||||
@ -32,7 +32,7 @@ postEExamNewR = do
|
|||||||
}
|
}
|
||||||
whenIsJust insertRes $ \eeId -> do
|
whenIsJust insertRes $ \eeId -> do
|
||||||
audit $ TransactionExternalExamEdit eeId
|
audit $ TransactionExternalExamEdit eeId
|
||||||
|
|
||||||
let eefOfficeSchools' = do
|
let eefOfficeSchools' = do
|
||||||
externalExamOfficeSchoolSchool <- Set.toList eefOfficeSchools
|
externalExamOfficeSchoolSchool <- Set.toList eefOfficeSchools
|
||||||
guard $ externalExamOfficeSchoolSchool /= eefSchool
|
guard $ externalExamOfficeSchoolSchool /= eefSchool
|
||||||
@ -41,7 +41,7 @@ postEExamNewR = do
|
|||||||
insertMany_ eefOfficeSchools'
|
insertMany_ eefOfficeSchools'
|
||||||
forM_ eefOfficeSchools' $ \ExternalExamOfficeSchool{..} ->
|
forM_ eefOfficeSchools' $ \ExternalExamOfficeSchool{..} ->
|
||||||
audit $ TransactionExternalExamOfficeSchoolEdit eeId externalExamOfficeSchoolSchool
|
audit $ TransactionExternalExamOfficeSchoolEdit eeId externalExamOfficeSchoolSchool
|
||||||
|
|
||||||
let (invites, adds) = partitionEithers $ Set.toList eefStaff
|
let (invites, adds) = partitionEithers $ Set.toList eefStaff
|
||||||
eefStaff' = do
|
eefStaff' = do
|
||||||
externalExamStaffUser <- adds
|
externalExamStaffUser <- adds
|
||||||
@ -50,7 +50,7 @@ postEExamNewR = do
|
|||||||
insertMany_ eefStaff'
|
insertMany_ eefStaff'
|
||||||
forM_ eefStaff' $ \ExternalExamStaff{..} ->
|
forM_ eefStaff' $ \ExternalExamStaff{..} ->
|
||||||
audit $ TransactionExternalExamStaffEdit eeId externalExamStaffUser
|
audit $ TransactionExternalExamStaffEdit eeId externalExamStaffUser
|
||||||
|
|
||||||
sinkInvitationsF externalExamStaffInvitationConfig $ map (, eeId, (InvDBDataExternalExamStaff, InvTokenDataExternalExamStaff)) invites
|
sinkInvitationsF externalExamStaffInvitationConfig $ map (, eeId, (InvDBDataExternalExamStaff, InvTokenDataExternalExamStaff)) invites
|
||||||
forM_ invites $ \invEmail ->
|
forM_ invites $ \invEmail ->
|
||||||
audit $ TransactionExternalExamStaffInviteEdit eeId invEmail
|
audit $ TransactionExternalExamStaffInviteEdit eeId invEmail
|
||||||
|
|||||||
@ -10,7 +10,7 @@ import qualified Data.Map as Map
|
|||||||
import qualified Data.Yaml as Yaml
|
import qualified Data.Yaml as Yaml
|
||||||
|
|
||||||
import qualified Control.Monad.State.Class as State
|
import qualified Control.Monad.State.Class as State
|
||||||
|
|
||||||
|
|
||||||
data HelpIdentOptions = HIUser | HIEmail | HIAnonymous
|
data HelpIdentOptions = HIUser | HIEmail | HIAnonymous
|
||||||
deriving (Eq, Ord, Bounded, Enum, Show, Read)
|
deriving (Eq, Ord, Bounded, Enum, Show, Read)
|
||||||
@ -58,7 +58,7 @@ helpForm mReferer mUid = renderWForm FormStandard $ do
|
|||||||
Nothing -> return $ pure Nothing
|
Nothing -> return $ pure Nothing
|
||||||
Just err ->
|
Just err ->
|
||||||
let prettyErr = decodeUtf8 $ Yaml.encode err
|
let prettyErr = decodeUtf8 $ Yaml.encode err
|
||||||
in optionalActionW
|
in optionalActionW
|
||||||
(err <$ aforced textareaField (fslI MsgHelpError) (Textarea prettyErr))
|
(err <$ aforced textareaField (fslI MsgHelpError) (Textarea prettyErr))
|
||||||
(fslI MsgHelpSendLastError)
|
(fslI MsgHelpSendLastError)
|
||||||
(Just True)
|
(Just True)
|
||||||
@ -69,7 +69,7 @@ helpForm mReferer mUid = renderWForm FormStandard $ do
|
|||||||
<*> hfSubject'
|
<*> hfSubject'
|
||||||
<*> hfRequest'
|
<*> hfRequest'
|
||||||
<*> hfError'
|
<*> hfError'
|
||||||
|
|
||||||
validateHelpForm :: FormValidator HelpForm Handler ()
|
validateHelpForm :: FormValidator HelpForm Handler ()
|
||||||
validateHelpForm = do
|
validateHelpForm = do
|
||||||
HelpForm{..} <- State.get
|
HelpForm{..} <- State.get
|
||||||
@ -99,7 +99,7 @@ postHelpR = do
|
|||||||
|
|
||||||
whenIsJust hfError $ \error' ->
|
whenIsJust hfError $ \error' ->
|
||||||
modifySessionJson SessionError $ assertM (/= error')
|
modifySessionJson SessionError $ assertM (/= error')
|
||||||
|
|
||||||
tell . pure =<< messageI Success MsgHelpSent
|
tell . pure =<< messageI Success MsgHelpSent
|
||||||
|
|
||||||
defaultLayout $ do
|
defaultLayout $ do
|
||||||
@ -111,5 +111,5 @@ postHelpR = do
|
|||||||
}
|
}
|
||||||
|
|
||||||
mFaqs <- (>>= \(mWgt, truncated) -> (, truncated) <$> mWgt) <$> traverse (faqsWidget $ Just 5) (Just <$> mReferer)
|
mFaqs <- (>>= \(mWgt, truncated) -> (, truncated) <$> mWgt) <$> traverse (faqsWidget $ Just 5) (Just <$> mReferer)
|
||||||
|
|
||||||
$(widgetFile "help")
|
$(widgetFile "help")
|
||||||
|
|||||||
@ -53,7 +53,7 @@ getInfoLecturerR =
|
|||||||
$(i18nWidgetFile "info-lecturer")
|
$(i18nWidgetFile "info-lecturer")
|
||||||
where
|
where
|
||||||
allocationInfo = $(i18nWidgetFile "allocation-info")
|
allocationInfo = $(i18nWidgetFile "allocation-info")
|
||||||
|
|
||||||
tooltipNew, tooltipProblem, tooltipPlanned, tooltipNewU2W :: WidgetFor UniWorX ()
|
tooltipNew, tooltipProblem, tooltipPlanned, tooltipNewU2W :: WidgetFor UniWorX ()
|
||||||
tooltipNew = [whamlet| _{MsgLecturerInfoTooltipNew} |]
|
tooltipNew = [whamlet| _{MsgLecturerInfoTooltipNew} |]
|
||||||
tooltipProblem = [whamlet| _{MsgLecturerInfoTooltipProblem} |]
|
tooltipProblem = [whamlet| _{MsgLecturerInfoTooltipProblem} |]
|
||||||
@ -64,7 +64,7 @@ getInfoLecturerR =
|
|||||||
probFeatInline = [whamlet| ^{iconTooltip tooltipProblem (Just IconProblem) True} |] -- to be used inside text blocks
|
probFeatInline = [whamlet| ^{iconTooltip tooltipProblem (Just IconProblem) True} |] -- to be used inside text blocks
|
||||||
plannedFeat = [whamlet| ^{iconTooltip tooltipPlanned (Just IconPlanned) False} |]
|
plannedFeat = [whamlet| ^{iconTooltip tooltipPlanned (Just IconPlanned) False} |]
|
||||||
plannedFeatInline = [whamlet| ^{iconTooltip tooltipPlanned (Just IconPlanned) True} |] -- to be used inside text blocks
|
plannedFeatInline = [whamlet| ^{iconTooltip tooltipPlanned (Just IconPlanned) True} |] -- to be used inside text blocks
|
||||||
|
|
||||||
-- new feature with given introduction date
|
-- new feature with given introduction date
|
||||||
newFeat :: Integer -> Int -> Int -> WidgetFor UniWorX ()
|
newFeat :: Integer -> Int -> Int -> WidgetFor UniWorX ()
|
||||||
newFeat year month day = do
|
newFeat year month day = do
|
||||||
|
|||||||
@ -21,7 +21,7 @@ data MaterialForm = MaterialForm
|
|||||||
, mfType :: Maybe (CI Text)
|
, mfType :: Maybe (CI Text)
|
||||||
, mfDescription :: Maybe Html
|
, mfDescription :: Maybe Html
|
||||||
, mfVisibleFrom :: Maybe UTCTime
|
, mfVisibleFrom :: Maybe UTCTime
|
||||||
, mfFiles :: Maybe FileUploads
|
, mfFiles :: Maybe FileUploads
|
||||||
}
|
}
|
||||||
|
|
||||||
makeMaterialForm :: CourseId -> Maybe MaterialForm -> Form MaterialForm
|
makeMaterialForm :: CourseId -> Maybe MaterialForm -> Form MaterialForm
|
||||||
@ -135,7 +135,7 @@ getMaterialListR tid ssh csh = do
|
|||||||
, ( "last-edit" , SortColumn (E.^. MaterialLastEdit) )
|
, ( "last-edit" , SortColumn (E.^. MaterialLastEdit) )
|
||||||
]
|
]
|
||||||
, dbtFilter = mconcat
|
, dbtFilter = mconcat
|
||||||
[ singletonMap "may-access" . FilterProjected $ \(Any b) dbr
|
[ singletonMap "may-access" . FilterProjected $ \(Any b) dbr
|
||||||
-> (== b) <$> hasReadAccessTo (matLink . materialName $ row2material dbr) :: DB Bool
|
-> (== b) <$> hasReadAccessTo (matLink . materialName $ row2material dbr) :: DB Bool
|
||||||
]
|
]
|
||||||
, dbtFilterUI = mempty
|
, dbtFilterUI = mempty
|
||||||
@ -347,4 +347,4 @@ getMArchiveR tid ssh csh mnm = do
|
|||||||
return materialFile
|
return materialFile
|
||||||
|
|
||||||
serveSomeFiles archiveName getMatQuery
|
serveSomeFiles archiveName getMatQuery
|
||||||
|
|
||||||
|
|||||||
@ -28,7 +28,7 @@ getMetricsR = selectRep $ do
|
|||||||
guardM . lift . existsBy $ UniqueUserGroupMember UserGroupMetrics uid
|
guardM . lift . existsBy $ UniqueUserGroupMember UserGroupMetrics uid
|
||||||
|
|
||||||
encodeBearer =<< bearerToken (HashSet.singleton . Left $ toJSON UserGroupMetrics) (Just $ HashSet.singleton MetricsR) Nothing (Just Nothing) Nothing
|
encodeBearer =<< bearerToken (HashSet.singleton . Left $ toJSON UserGroupMetrics) (Just $ HashSet.singleton MetricsR) Nothing (Just Nothing) Nothing
|
||||||
|
|
||||||
defaultLayout $ do
|
defaultLayout $ do
|
||||||
setTitleI MsgTitleMetrics
|
setTitleI MsgTitleMetrics
|
||||||
$(widgetFile "metrics")
|
$(widgetFile "metrics")
|
||||||
|
|||||||
@ -29,7 +29,7 @@ getNewsR = do
|
|||||||
|
|
||||||
when (is _Nothing muid) $
|
when (is _Nothing muid) $
|
||||||
notificationWidget NotificationBroad Info $(i18nWidgetFile "pitch")
|
notificationWidget NotificationBroad Info $(i18nWidgetFile "pitch")
|
||||||
|
|
||||||
case muid of
|
case muid of
|
||||||
Just uid -> do
|
Just uid -> do
|
||||||
newsUpcomingExams uid
|
newsUpcomingExams uid
|
||||||
@ -51,7 +51,7 @@ newsSystemMessages = do
|
|||||||
mkHideForm smId SystemMessage{..} = liftHandler $ do
|
mkHideForm smId SystemMessage{..} = liftHandler $ do
|
||||||
cID <- encrypt smId
|
cID <- encrypt smId
|
||||||
hidden <- getSystemMessageState smId <&> \UserSystemMessageState{..} -> userSystemMessageHidden > Just systemMessageLastUnhide
|
hidden <- getSystemMessageState smId <&> \UserSystemMessageState{..} -> userSystemMessageHidden > Just systemMessageLastUnhide
|
||||||
|
|
||||||
(btnView, btnEnctype) <- generateFormPost . buttonForm' $ bool [BtnSystemMessageHide] [BtnSystemMessageUnhide] hidden
|
(btnView, btnEnctype) <- generateFormPost . buttonForm' $ bool [BtnSystemMessageHide] [BtnSystemMessageUnhide] hidden
|
||||||
return $ wrapForm btnView def
|
return $ wrapForm btnView def
|
||||||
{ formSubmit = FormNoSubmit
|
{ formSubmit = FormNoSubmit
|
||||||
@ -65,7 +65,7 @@ newsSystemMessages = do
|
|||||||
tell $ Any hidden
|
tell $ Any hidden
|
||||||
|
|
||||||
return $ guardOn (not hidden || showHidden) (smId, sm, trans, hidden)
|
return $ guardOn (not hidden || showHidden) (smId, sm, trans, hidden)
|
||||||
|
|
||||||
(messages', Any anyHidden) <- liftHandler . runDB . runConduit . C.runWriterLC $
|
(messages', Any anyHidden) <- liftHandler . runDB . runConduit . C.runWriterLC $
|
||||||
transPipe lift (selectKeys [] [])
|
transPipe lift (selectKeys [] [])
|
||||||
.| C.filterM (hasReadAccessTo . MessageR <=< encrypt)
|
.| C.filterM (hasReadAccessTo . MessageR <=< encrypt)
|
||||||
@ -87,7 +87,7 @@ newsUpcomingSheets :: UserId -> Widget
|
|||||||
newsUpcomingSheets uid = do
|
newsUpcomingSheets uid = do
|
||||||
cTime <- liftIO getCurrentTime
|
cTime <- liftIO getCurrentTime
|
||||||
let noActiveToCutoff = toMidnight . addGregorianDurationRollOver (scaleCalendarDiffDays (-1) calendarMonth) $ utctDay cTime
|
let noActiveToCutoff = toMidnight . addGregorianDurationRollOver (scaleCalendarDiffDays (-1) calendarMonth) $ utctDay cTime
|
||||||
|
|
||||||
let tableData :: E.LeftOuterJoin
|
let tableData :: E.LeftOuterJoin
|
||||||
(E.InnerJoin (E.InnerJoin (E.SqlExpr (Entity CourseParticipant)) (E.SqlExpr (Entity Course))) (E.SqlExpr (Entity Sheet)))
|
(E.InnerJoin (E.InnerJoin (E.SqlExpr (Entity CourseParticipant)) (E.SqlExpr (Entity Course))) (E.SqlExpr (Entity Sheet)))
|
||||||
(E.InnerJoin (E.SqlExpr (Maybe (Entity Submission))) (E.SqlExpr (Maybe (Entity SubmissionUser))))
|
(E.InnerJoin (E.SqlExpr (Maybe (Entity Submission))) (E.SqlExpr (Maybe (Entity SubmissionUser))))
|
||||||
@ -104,12 +104,12 @@ newsUpcomingSheets uid = do
|
|||||||
E.on $ course E.^. CourseId E.==. sheet E.^. SheetCourse
|
E.on $ course E.^. CourseId E.==. sheet E.^. SheetCourse
|
||||||
E.on $ course E.^. CourseId E.==. participant E.^. CourseParticipantCourse
|
E.on $ course E.^. CourseId E.==. participant E.^. CourseParticipantCourse
|
||||||
|
|
||||||
let showSheetNoActiveTo =
|
let showSheetNoActiveTo =
|
||||||
E.maybe E.false (E.>=. E.val noActiveToCutoff) (sheet E.^. SheetActiveFrom)
|
E.maybe E.false (E.>=. E.val noActiveToCutoff) (sheet E.^. SheetActiveFrom)
|
||||||
E.||. E.maybe E.false (E.>=. E.val noActiveToCutoff) (sheet E.^. SheetVisibleFrom)
|
E.||. E.maybe E.false (E.>=. E.val noActiveToCutoff) (sheet E.^. SheetVisibleFrom)
|
||||||
E.||. E.maybe E.false (E.>=. E.val noActiveToCutoff) (sheet E.^. SheetHintFrom)
|
E.||. E.maybe E.false (E.>=. E.val noActiveToCutoff) (sheet E.^. SheetHintFrom)
|
||||||
E.||. E.maybe E.false (E.>=. E.val noActiveToCutoff) (sheet E.^. SheetSolutionFrom)
|
E.||. E.maybe E.false (E.>=. E.val noActiveToCutoff) (sheet E.^. SheetSolutionFrom)
|
||||||
|
|
||||||
E.where_ $ participant E.^. CourseParticipantUser E.==. E.val uid
|
E.where_ $ participant E.^. CourseParticipantUser E.==. E.val uid
|
||||||
E.&&. participant E.^. CourseParticipantState E.==. E.val CourseParticipantActive
|
E.&&. participant E.^. CourseParticipantState E.==. E.val CourseParticipantActive
|
||||||
E.&&. E.maybe showSheetNoActiveTo (E.>=. E.val cTime) (sheet E.^. SheetActiveTo)
|
E.&&. E.maybe showSheetNoActiveTo (E.>=. E.val cTime) (sheet E.^. SheetActiveTo)
|
||||||
|
|||||||
@ -35,7 +35,7 @@ instance ToNamedRecord ParticipantEntry where
|
|||||||
|
|
||||||
instance DefaultOrdered ParticipantEntry where
|
instance DefaultOrdered ParticipantEntry where
|
||||||
headerOrder _ = Csv.header ["course", "email"]
|
headerOrder _ = Csv.header ["course", "email"]
|
||||||
|
|
||||||
|
|
||||||
getParticipantsListR :: Handler Html
|
getParticipantsListR :: Handler Html
|
||||||
getParticipantsListR = do
|
getParticipantsListR = do
|
||||||
@ -52,10 +52,10 @@ getParticipantsListR = do
|
|||||||
|
|
||||||
schoolTerms' <- flip filterM schoolTerms'' $ \(E.Value ssh, E.Value tid) ->
|
schoolTerms' <- flip filterM schoolTerms'' $ \(E.Value ssh, E.Value tid) ->
|
||||||
hasReadAccessTo $ ParticipantsR tid ssh
|
hasReadAccessTo $ ParticipantsR tid ssh
|
||||||
|
|
||||||
let schoolTerms :: Set (SchoolId, TermId)
|
let schoolTerms :: Set (SchoolId, TermId)
|
||||||
schoolTerms = setOf (folded . $(multifocusG 2) (_1 . _Value) (_2 . _Value)) schoolTerms'
|
schoolTerms = setOf (folded . $(multifocusG 2) (_1 . _Value) (_2 . _Value)) schoolTerms'
|
||||||
|
|
||||||
siteLayoutMsg MsgMenuParticipantsList $ do
|
siteLayoutMsg MsgMenuParticipantsList $ do
|
||||||
setTitleI MsgMenuParticipantsList
|
setTitleI MsgMenuParticipantsList
|
||||||
|
|
||||||
|
|||||||
@ -227,7 +227,7 @@ notificationForm template = wFormToAForm $ do
|
|||||||
validateSettings :: User -> FormValidator SettingsForm Handler ()
|
validateSettings :: User -> FormValidator SettingsForm Handler ()
|
||||||
validateSettings User{..} = do
|
validateSettings User{..} = do
|
||||||
userDisplayName' <- use _stgDisplayName
|
userDisplayName' <- use _stgDisplayName
|
||||||
|
|
||||||
guardValidation MsgUserDisplayNameInvalid $
|
guardValidation MsgUserDisplayNameInvalid $
|
||||||
validDisplayName userTitle userFirstName userSurname userDisplayName'
|
validDisplayName userTitle userFirstName userSurname userDisplayName'
|
||||||
|
|
||||||
@ -812,7 +812,7 @@ postSetDisplayEmailR = do
|
|||||||
siteLayoutMsg MsgTitleChangeUserDisplayEmail $ do
|
siteLayoutMsg MsgTitleChangeUserDisplayEmail $ do
|
||||||
setTitleI MsgTitleChangeUserDisplayEmail
|
setTitleI MsgTitleChangeUserDisplayEmail
|
||||||
$(i18nWidgetFile "set-display-email")
|
$(i18nWidgetFile "set-display-email")
|
||||||
|
|
||||||
getCsvOptionsR, postCsvOptionsR :: Handler Html
|
getCsvOptionsR, postCsvOptionsR :: Handler Html
|
||||||
getCsvOptionsR = postCsvOptionsR
|
getCsvOptionsR = postCsvOptionsR
|
||||||
postCsvOptionsR = do
|
postCsvOptionsR = do
|
||||||
|
|||||||
@ -8,14 +8,14 @@ import qualified Database.Esqueleto as E
|
|||||||
import qualified Data.Set as Set
|
import qualified Data.Set as Set
|
||||||
import qualified Data.CaseInsensitive as CI
|
import qualified Data.CaseInsensitive as CI
|
||||||
import qualified Data.Text as Text
|
import qualified Data.Text as Text
|
||||||
|
|
||||||
|
|
||||||
getSchoolListR :: Handler Html
|
getSchoolListR :: Handler Html
|
||||||
getSchoolListR = do
|
getSchoolListR = do
|
||||||
let
|
let
|
||||||
schoolLink :: SchoolId -> SomeRoute UniWorX
|
schoolLink :: SchoolId -> SomeRoute UniWorX
|
||||||
schoolLink ssh = SomeRoute $ SchoolR ssh SchoolEditR
|
schoolLink ssh = SomeRoute $ SchoolR ssh SchoolEditR
|
||||||
|
|
||||||
dbtSQLQuery :: E.SqlExpr (Entity School) -> E.SqlQuery _
|
dbtSQLQuery :: E.SqlExpr (Entity School) -> E.SqlQuery _
|
||||||
dbtSQLQuery = return
|
dbtSQLQuery = return
|
||||||
|
|
||||||
@ -49,7 +49,7 @@ getSchoolListR = do
|
|||||||
|
|
||||||
psValidator = def
|
psValidator = def
|
||||||
& defaultSorting [SortAscBy "school-name"]
|
& defaultSorting [SortAscBy "school-name"]
|
||||||
|
|
||||||
|
|
||||||
table <- runDB $ dbTableWidget' psValidator DBTable{..}
|
table <- runDB $ dbTableWidget' psValidator DBTable{..}
|
||||||
|
|
||||||
@ -89,7 +89,7 @@ getSchoolEditR, postSchoolEditR :: SchoolId -> Handler Html
|
|||||||
getSchoolEditR = postSchoolEditR
|
getSchoolEditR = postSchoolEditR
|
||||||
postSchoolEditR ssh = do
|
postSchoolEditR ssh = do
|
||||||
sForm <- runDB $ schoolToForm ssh
|
sForm <- runDB $ schoolToForm ssh
|
||||||
|
|
||||||
((sfResult, sfView), sfEnctype) <- runFormPost sForm
|
((sfResult, sfView), sfEnctype) <- runFormPost sForm
|
||||||
|
|
||||||
formResult sfResult $ \SchoolForm{..} -> do
|
formResult sfResult $ \SchoolForm{..} -> do
|
||||||
|
|||||||
@ -20,7 +20,7 @@ import Handler.Sheet.New as Handler.Sheet
|
|||||||
import Handler.Sheet.Show as Handler.Sheet
|
import Handler.Sheet.Show as Handler.Sheet
|
||||||
import Handler.Sheet.PersonalisedFiles as Handler.Sheet (getSPersonalFilesR)
|
import Handler.Sheet.PersonalisedFiles as Handler.Sheet (getSPersonalFilesR)
|
||||||
|
|
||||||
|
|
||||||
getSIsCorrR :: TermId -> SchoolId -> CourseShorthand -> SheetName -> Handler Html
|
getSIsCorrR :: TermId -> SchoolId -> CourseShorthand -> SheetName -> Handler Html
|
||||||
-- NOTE: The route SIsCorrR is only used to verfify corrector access rights to given sheet!
|
-- NOTE: The route SIsCorrR is only used to verfify corrector access rights to given sheet!
|
||||||
getSIsCorrR _ _ _ shn =
|
getSIsCorrR _ _ _ shn =
|
||||||
|
|||||||
@ -6,7 +6,7 @@ module Handler.Sheet.Current
|
|||||||
import Import
|
import Import
|
||||||
|
|
||||||
import Utils.Sheet
|
import Utils.Sheet
|
||||||
|
|
||||||
|
|
||||||
getSheetCurrentR :: TermId -> SchoolId -> CourseShorthand -> Handler Void
|
getSheetCurrentR :: TermId -> SchoolId -> CourseShorthand -> Handler Void
|
||||||
getSheetCurrentR tid ssh csh = do
|
getSheetCurrentR tid ssh csh = do
|
||||||
|
|||||||
@ -86,7 +86,7 @@ handleSheetEdit tid ssh csh msId template dbAction = do
|
|||||||
, sheetAutoDistribute = sfAutoDistribute
|
, sheetAutoDistribute = sfAutoDistribute
|
||||||
, sheetAnonymousCorrection = sfAnonymousCorrection
|
, sheetAnonymousCorrection = sfAnonymousCorrection
|
||||||
, sheetRequireExamRegistration = sfRequireExamRegistration
|
, sheetRequireExamRegistration = sfRequireExamRegistration
|
||||||
, sheetAllowNonPersonalisedSubmission = fromMaybe True $ spffAllowNonPersonalisedSubmission <$> sfPersonalF
|
, sheetAllowNonPersonalisedSubmission = maybe True spffAllowNonPersonalisedSubmission sfPersonalF
|
||||||
}
|
}
|
||||||
mbsid <- dbAction newSheet
|
mbsid <- dbAction newSheet
|
||||||
case mbsid of
|
case mbsid of
|
||||||
@ -98,7 +98,7 @@ handleSheetEdit tid ssh csh msId template dbAction = do
|
|||||||
insertSheetFile' sid SheetMarking $ fromMaybe (return ()) sfMarkingF
|
insertSheetFile' sid SheetMarking $ fromMaybe (return ()) sfMarkingF
|
||||||
runConduit $
|
runConduit $
|
||||||
maybe (return ()) (transPipe liftHandler) (spffFiles =<< sfPersonalF)
|
maybe (return ()) (transPipe liftHandler) (spffFiles =<< sfPersonalF)
|
||||||
.| sinkPersonalisedSheetFiles cid sid (fromMaybe False $ spffFilesKeepExisting <$> sfPersonalF)
|
.| sinkPersonalisedSheetFiles cid sid (maybe False spffFilesKeepExisting sfPersonalF)
|
||||||
insert_ $ SheetEdit aid actTime sid
|
insert_ $ SheetEdit aid actTime sid
|
||||||
addMessageI Success $ MsgSheetEditOk tid ssh csh sfName
|
addMessageI Success $ MsgSheetEditOk tid ssh csh sfName
|
||||||
-- Sanity checks generating warnings only, but not errors!
|
-- Sanity checks generating warnings only, but not errors!
|
||||||
@ -123,11 +123,11 @@ handleSheetEdit tid ssh csh msId template dbAction = do
|
|||||||
|
|
||||||
deleteWhere [InvitationFor ==. invRef @SheetCorrector sid, InvitationEmail /<-. toListOf (folded . _1) invites]
|
deleteWhere [InvitationFor ==. invRef @SheetCorrector sid, InvitationEmail /<-. toListOf (folded . _1) invites]
|
||||||
sinkInvitationsF correctorInvitationConfig invites
|
sinkInvitationsF correctorInvitationConfig invites
|
||||||
|
|
||||||
return True
|
return True
|
||||||
when saveOkay $
|
when saveOkay $
|
||||||
redirect $ CSheetR tid ssh csh sfName SShowR -- redirect must happen outside of runDB
|
redirect $ CSheetR tid ssh csh sfName SShowR -- redirect must happen outside of runDB
|
||||||
(FormFailure msgs) -> forM_ msgs $ (addMessage Error) . toHtml
|
(FormFailure msgs) -> forM_ msgs $ addMessage Error . toHtml
|
||||||
_ -> runDB $ warnTermDays tid $ Map.fromList [ (date,name) | (Just date, name) <-
|
_ -> runDB $ warnTermDays tid $ Map.fromList [ (date,name) | (Just date, name) <-
|
||||||
[(sfVisibleFrom =<< template, MsgSheetVisibleFrom)
|
[(sfVisibleFrom =<< template, MsgSheetVisibleFrom)
|
||||||
,(sfActiveFrom =<< template, MsgSheetActiveFrom)
|
,(sfActiveFrom =<< template, MsgSheetActiveFrom)
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
module Handler.Sheet.Form
|
module Handler.Sheet.Form
|
||||||
( SheetForm(..), SheetPersonalisedFilesForm(..), Loads
|
( SheetForm(..), SheetPersonalisedFilesForm(..), Loads
|
||||||
, makeSheetForm
|
, makeSheetForm
|
||||||
, getFtIdMap
|
, getFtIdMap
|
||||||
) where
|
) where
|
||||||
|
|
||||||
import Import
|
import Import
|
||||||
@ -97,7 +97,7 @@ makeSheetForm cId msId template = identifyForm FIDsheet . validateForm validateS
|
|||||||
<*> apopt checkBoxField (fslI MsgAutoAssignCorrs) (sfAutoDistribute <$> template)
|
<*> apopt checkBoxField (fslI MsgAutoAssignCorrs) (sfAutoDistribute <$> template)
|
||||||
<*> aopt htmlField (fslI MsgSheetMarking) (sfMarkingText <$> template)
|
<*> aopt htmlField (fslI MsgSheetMarking) (sfMarkingText <$> template)
|
||||||
<*> apopt checkBoxField (fslI MsgSheetAnonymousCorrection & setTooltip MsgSheetAnonymousCorrectionTip) (sfAnonymousCorrection <$> template)
|
<*> apopt checkBoxField (fslI MsgSheetAnonymousCorrection & setTooltip MsgSheetAnonymousCorrectionTip) (sfAnonymousCorrection <$> template)
|
||||||
<*> correctorForm (fromMaybe mempty $ sfCorrectors <$> template)
|
<*> correctorForm (maybe mempty sfCorrectors template)
|
||||||
where
|
where
|
||||||
makeSheetPersonalisedFilesForm :: Maybe SheetPersonalisedFilesForm -> MForm Handler (AForm Handler SheetPersonalisedFilesForm)
|
makeSheetPersonalisedFilesForm :: Maybe SheetPersonalisedFilesForm -> MForm Handler (AForm Handler SheetPersonalisedFilesForm)
|
||||||
makeSheetPersonalisedFilesForm template' = do
|
makeSheetPersonalisedFilesForm template' = do
|
||||||
@ -143,10 +143,10 @@ makeSheetForm cId msId template = identifyForm FIDsheet . validateForm validateS
|
|||||||
validateSheet = do
|
validateSheet = do
|
||||||
SheetForm{..} <- State.get
|
SheetForm{..} <- State.get
|
||||||
|
|
||||||
guardValidation MsgSheetErrVisibility $ NTop sfVisibleFrom <= NTop sfActiveFrom
|
guardValidation MsgSheetErrVisibility $ NTop sfVisibleFrom <= NTop sfActiveFrom
|
||||||
guardValidation MsgSheetErrDeadlineEarly $ NTop sfActiveFrom <= NTop sfActiveTo
|
guardValidation MsgSheetErrDeadlineEarly $ NTop sfActiveFrom <= NTop sfActiveTo
|
||||||
guardValidation MsgSheetErrHintEarly $ NTop sfHintFrom >= NTop sfActiveFrom
|
guardValidation MsgSheetErrHintEarly $ NTop sfHintFrom >= NTop sfActiveFrom
|
||||||
guardValidation MsgSheetErrSolutionEarly $ NTop sfSolutionFrom >= NTop sfActiveTo
|
guardValidation MsgSheetErrSolutionEarly $ NTop sfSolutionFrom >= NTop sfActiveTo
|
||||||
|
|
||||||
guardValidation MsgSheetErrVisibleWithoutActive $ is _Just sfActiveFrom || is _Nothing sfVisibleFrom
|
guardValidation MsgSheetErrVisibleWithoutActive $ is _Just sfActiveFrom || is _Nothing sfVisibleFrom
|
||||||
|
|
||||||
@ -162,7 +162,7 @@ correctorForm loads' = wFormToAForm $ do
|
|||||||
loads :: Map (Either UserEmail UserId) (CorrectorState, Load)
|
loads :: Map (Either UserEmail UserId) (CorrectorState, Load)
|
||||||
loads = loads' <&> \(InvDBDataSheetCorrector load cState, InvTokenDataSheetCorrector) -> (cState, load)
|
loads = loads' <&> \(InvDBDataSheetCorrector load cState, InvTokenDataSheetCorrector) -> (cState, load)
|
||||||
|
|
||||||
countTutRes <- wpopt checkBoxField (fslI MsgCountTutProp & setTooltip MsgCountTutPropTip) . Just . any (\(_, Load{..}) -> fromMaybe False byTutorial) $ Map.elems loads
|
countTutRes <- wpopt checkBoxField (fslI MsgCountTutProp & setTooltip MsgCountTutPropTip) . Just . any (\(_, Load{..}) -> Just True == byTutorial) $ Map.elems loads
|
||||||
|
|
||||||
|
|
||||||
let
|
let
|
||||||
@ -173,7 +173,7 @@ correctorForm loads' = wFormToAForm $ do
|
|||||||
E.on $ sheet E.^. SheetId E.==. sheetCorrector E.^. SheetCorrectorSheet
|
E.on $ sheet E.^. SheetId E.==. sheetCorrector E.^. SheetCorrectorSheet
|
||||||
E.on $ sheetCorrector E.^. SheetCorrectorUser E.==. user E.^. UserId
|
E.on $ sheetCorrector E.^. SheetCorrectorUser E.==. user E.^. UserId
|
||||||
E.where_ $ lecturer E.^. LecturerUser E.==. E.val userId
|
E.where_ $ lecturer E.^. LecturerUser E.==. E.val userId
|
||||||
E.orderBy $ [E.asc $ user E.^. UserSurname, E.asc $ user E.^. UserDisplayName]
|
E.orderBy [E.asc $ user E.^. UserSurname, E.asc $ user E.^. UserDisplayName]
|
||||||
return user
|
return user
|
||||||
|
|
||||||
miAdd :: ListPosition
|
miAdd :: ListPosition
|
||||||
@ -199,7 +199,7 @@ correctorForm loads' = wFormToAForm $ do
|
|||||||
miCell _ userIdent initRes nudge csrf = do
|
miCell _ userIdent initRes nudge csrf = do
|
||||||
(stateRes, stateView) <- mreq (selectField optionsFinite) (fslI MsgSheetCorrectorState & addName (nudge "state")) $ (fst <$> initRes) <|> Just CorrectorNormal
|
(stateRes, stateView) <- mreq (selectField optionsFinite) (fslI MsgSheetCorrectorState & addName (nudge "state")) $ (fst <$> initRes) <|> Just CorrectorNormal
|
||||||
(byTutRes, byTutView) <- mreq checkBoxField ("" & addName (nudge "bytut")) $ (isJust . byTutorial . snd <$> initRes) <|> Just False
|
(byTutRes, byTutView) <- mreq checkBoxField ("" & addName (nudge "bytut")) $ (isJust . byTutorial . snd <$> initRes) <|> Just False
|
||||||
(propRes, propView) <- mreq (checkBool (>= 0) MsgProportionNegative $ rationalField) (fslI MsgSheetCorrectorProportion & addName (nudge "prop")) $ (byProportion . snd <$> initRes) <|> Just 0
|
(propRes, propView) <- mreq (checkBool (>= 0) MsgProportionNegative rationalField) (fslI MsgSheetCorrectorProportion & addName (nudge "prop")) $ (byProportion . snd <$> initRes) <|> Just 0
|
||||||
let
|
let
|
||||||
res :: FormResult (CorrectorState, Load)
|
res :: FormResult (CorrectorState, Load)
|
||||||
res = (,) <$> stateRes <*> (Load <$> tutRes' <*> propRes)
|
res = (,) <$> stateRes <*> (Load <$> tutRes' <*> propRes)
|
||||||
@ -251,7 +251,7 @@ correctorForm loads' = wFormToAForm $ do
|
|||||||
|
|
||||||
postProcess :: Map ListPosition (Either UserEmail UserId, (CorrectorState, Load)) -> Loads
|
postProcess :: Map ListPosition (Either UserEmail UserId, (CorrectorState, Load)) -> Loads
|
||||||
postProcess = Map.fromList . map postProcess' . Map.elems
|
postProcess = Map.fromList . map postProcess' . Map.elems
|
||||||
where
|
where
|
||||||
postProcess' :: (Either UserEmail UserId, (CorrectorState, Load)) -> (Either UserEmail UserId, (InvitationDBData SheetCorrector, InvitationTokenData SheetCorrector))
|
postProcess' :: (Either UserEmail UserId, (CorrectorState, Load)) -> (Either UserEmail UserId, (InvitationDBData SheetCorrector, InvitationTokenData SheetCorrector))
|
||||||
postProcess' = over _2 $ \(cState, load) -> (InvDBDataSheetCorrector load cState, InvTokenDataSheetCorrector)
|
postProcess' = over _2 $ \(cState, load) -> (InvDBDataSheetCorrector load cState, InvTokenDataSheetCorrector)
|
||||||
|
|
||||||
|
|||||||
@ -69,14 +69,14 @@ getSheetListR tid ssh csh = do
|
|||||||
, sortable Nothing (i18nCell MsgSubmission)
|
, sortable Nothing (i18nCell MsgSubmission)
|
||||||
$ \DBRow{dbrOutput=(Entity _ Sheet{..}, _, mbSub, _)} -> case mbSub of
|
$ \DBRow{dbrOutput=(Entity _ Sheet{..}, _, mbSub, _)} -> case mbSub of
|
||||||
Nothing -> mempty
|
Nothing -> mempty
|
||||||
(Just (Entity sid Submission{..})) ->
|
(Just (Entity sid Submission{})) ->
|
||||||
let mkCid = encrypt sid -- TODO: executed twice
|
let mkCid = encrypt sid -- TODO: executed twice
|
||||||
mkRoute = do
|
mkRoute = do
|
||||||
cid' <- mkCid
|
cid' <- mkCid
|
||||||
return $ CSubmissionR tid ssh csh sheetName cid' SubShowR
|
return $ CSubmissionR tid ssh csh sheetName cid' SubShowR
|
||||||
in anchorCellM mkRoute (mkCid >>= \cid2 -> [whamlet|#{cid2}|])
|
in anchorCellM mkRoute (mkCid >>= \cid2 -> [whamlet|#{cid2}|])
|
||||||
, sortable (Just "rating") (i18nCell MsgRating)
|
, sortable (Just "rating") (i18nCell MsgRating)
|
||||||
$ \DBRow{dbrOutput=(Entity _ Sheet{..}, _, mbSub,_)} ->
|
$ \DBRow{dbrOutput=(Entity _ Sheet{..}, _, mbSub,_)} ->
|
||||||
let stats = sheetTypeSum sheetType in -- for statistics over all shown rows
|
let stats = sheetTypeSum sheetType in -- for statistics over all shown rows
|
||||||
case mbSub of
|
case mbSub of
|
||||||
Nothing -> cellTell mempty $ stats Nothing
|
Nothing -> cellTell mempty $ stats Nothing
|
||||||
|
|||||||
@ -11,6 +11,8 @@ import qualified Data.ByteString.Base64 as Base64 (encode, decodeLenient)
|
|||||||
import qualified Data.Binary as Binary (encode)
|
import qualified Data.Binary as Binary (encode)
|
||||||
import qualified Crypto.KDF.HKDF as HKDF
|
import qualified Crypto.KDF.HKDF as HKDF
|
||||||
|
|
||||||
|
{-# ANN module ("HLint: ignore Use newtype instead of data" :: String) #-}
|
||||||
|
|
||||||
|
|
||||||
data StorageKeyType
|
data StorageKeyType
|
||||||
= SKTExamCorrect
|
= SKTExamCorrect
|
||||||
@ -64,7 +66,7 @@ postStorageKeyR = do
|
|||||||
timestamp = if
|
timestamp = if
|
||||||
| Just ts <- skReqTimestamp, timestampInBounds -> ts
|
| Just ts <- skReqTimestamp, timestampInBounds -> ts
|
||||||
| otherwise -> now
|
| otherwise -> now
|
||||||
|
|
||||||
salt <- let sltSize = hashDigestSize SHA3_256 in if
|
salt <- let sltSize = hashDigestSize SHA3_256 in if
|
||||||
| Just slt <- Base64.decodeLenient . encodeUtf8 <$> skReqSalt
|
| Just slt <- Base64.decodeLenient . encodeUtf8 <$> skReqSalt
|
||||||
, timestampInBounds
|
, timestampInBounds
|
||||||
|
|||||||
@ -30,7 +30,7 @@ import Import
|
|||||||
|
|
||||||
import qualified Database.Esqueleto as E
|
import qualified Database.Esqueleto as E
|
||||||
|
|
||||||
|
|
||||||
getSubmissionOwnR :: TermId -> SchoolId -> CourseShorthand -> SheetName -> Handler Html
|
getSubmissionOwnR :: TermId -> SchoolId -> CourseShorthand -> SheetName -> Handler Html
|
||||||
-- For security reasons (unauthorized users not being allowed to have
|
-- For security reasons (unauthorized users not being allowed to have
|
||||||
-- guesses about which sheets/courses exist confirmed) this handlers
|
-- guesses about which sheets/courses exist confirmed) this handlers
|
||||||
|
|||||||
@ -3,7 +3,7 @@ module Handler.Submission.Assign
|
|||||||
, getCAssignR, postCAssignR
|
, getCAssignR, postCAssignR
|
||||||
, getSAssignR, postSAssignR
|
, getSAssignR, postSAssignR
|
||||||
) where
|
) where
|
||||||
|
|
||||||
import Import hiding (link, unzip)
|
import Import hiding (link, unzip)
|
||||||
|
|
||||||
import Handler.Utils hiding (colSchool)
|
import Handler.Utils hiding (colSchool)
|
||||||
@ -74,7 +74,7 @@ postSAssignR tid ssh csh shn = do
|
|||||||
assignHandler :: TermId -> SchoolId -> CourseShorthand -> CourseId -> [SheetId] -> Handler Html
|
assignHandler :: TermId -> SchoolId -> CourseShorthand -> CourseId -> [SheetId] -> Handler Html
|
||||||
assignHandler tid ssh csh cid assignSids = do
|
assignHandler tid ssh csh cid assignSids = do
|
||||||
currentRoute <- fromMaybe (error "assignHandler called from 404-handler") <$> liftHandler getCurrentRoute
|
currentRoute <- fromMaybe (error "assignHandler called from 404-handler") <$> liftHandler getCurrentRoute
|
||||||
|
|
||||||
-- gather data
|
-- gather data
|
||||||
(orderedSheetNames, assignSheetNames, nrParticipants, groupsPossible, infoMap, correctorMap, assignment, ((btnViews, btnCsrf), btnEncoding)) <- runDB $ do
|
(orderedSheetNames, assignSheetNames, nrParticipants, groupsPossible, infoMap, correctorMap, assignment, ((btnViews, btnCsrf), btnEncoding)) <- runDB $ do
|
||||||
-- cid <- getKeyBy404 $ TermSchoolCourseShort tid ssh csh
|
-- cid <- getKeyBy404 $ TermSchoolCourseShort tid ssh csh
|
||||||
@ -97,7 +97,7 @@ assignHandler tid ssh csh cid assignSids = do
|
|||||||
assignSheetNames' = sheetName <$> mapMaybe (`Map.lookup` sheets) assignSids'
|
assignSheetNames' = sheetName <$> mapMaybe (`Map.lookup` sheets) assignSids'
|
||||||
|
|
||||||
assignButtons = Map.fromSet (maybe BtnSubmissionsAssignAll BtnSubmissionsAssign) $ Set.fromList . bool (Nothing :) id (null sheetList) $ map Just assignSheetNames'
|
assignButtons = Map.fromSet (maybe BtnSubmissionsAssignAll BtnSubmissionsAssign) $ Set.fromList . bool (Nothing :) id (null sheetList) $ map Just assignSheetNames'
|
||||||
|
|
||||||
((btnResult, btnViews'), btnEncoding) <- runFormPost . identifyForm FIDAssignSubmissions $ \csrf ->
|
((btnResult, btnViews'), btnEncoding) <- runFormPost . identifyForm FIDAssignSubmissions $ \csrf ->
|
||||||
fmap (over _1 (asum . fmap (hoistMaybe =<<)) . over _2 (, csrf) . unzip) . for assignButtons $ \btn -> mopt (buttonField btn) "" Nothing
|
fmap (over _1 (asum . fmap (hoistMaybe =<<)) . over _2 (, csrf) . unzip) . for assignButtons $ \btn -> mopt (buttonField btn) "" Nothing
|
||||||
|
|
||||||
@ -132,7 +132,7 @@ assignHandler tid ssh csh cid assignSids = do
|
|||||||
| otherwise -> do
|
| otherwise -> do
|
||||||
addMessageI Error $ MsgSheetsUnassignable $ CI.original shn
|
addMessageI Error $ MsgSheetsUnassignable $ CI.original shn
|
||||||
return Nothing
|
return Nothing
|
||||||
if | null sub_ok && null sub_fail ->
|
if | null sub_ok && null sub_fail ->
|
||||||
return $ Map.insert shn (status, countMapElems plan, deficit) acc
|
return $ Map.insert shn (status, countMapElems plan, deficit) acc
|
||||||
| otherwise -> do
|
| otherwise -> do
|
||||||
(plan', deficit') <- lift $ handle ignoreExceptions $ planSubmissions sid Nothing
|
(plan', deficit') <- lift $ handle ignoreExceptions $ planSubmissions sid Nothing
|
||||||
@ -280,7 +280,7 @@ assignHandler tid ssh csh cid assignSids = do
|
|||||||
|
|
||||||
doWrap $(widgetFile "corrections-overview")
|
doWrap $(widgetFile "corrections-overview")
|
||||||
|
|
||||||
|
|
||||||
data ButtonSubmissionsAssign
|
data ButtonSubmissionsAssign
|
||||||
= BtnSubmissionsAssign SheetName
|
= BtnSubmissionsAssign SheetName
|
||||||
| BtnSubmissionsAssignAll
|
| BtnSubmissionsAssignAll
|
||||||
|
|||||||
@ -51,7 +51,7 @@ postCorrectionR tid ssh csh shn cid = do
|
|||||||
MsgRenderer mr <- getMsgRenderer
|
MsgRenderer mr <- getMsgRenderer
|
||||||
case results of
|
case results of
|
||||||
[(Entity cId Course{..}, Entity shId Sheet{..}, Entity _ subm@Submission{..}, corrector, E.Value filesCorrected)] -> do
|
[(Entity cId Course{..}, Entity shId Sheet{..}, Entity _ subm@Submission{..}, corrector, E.Value filesCorrected)] -> do
|
||||||
let ratingComment = fmap Text.strip submissionRatingComment >>= (\c -> c <$ guard (not $ null c))
|
let ratingComment = submissionRatingComment >>= (\c -> c <$ guard (not $ null c)) . Text.strip
|
||||||
pointsForm = case sheetType of
|
pointsForm = case sheetType of
|
||||||
NotGraded
|
NotGraded
|
||||||
-> pure Nothing
|
-> pure Nothing
|
||||||
@ -67,7 +67,7 @@ postCorrectionR tid ssh csh shn cid = do
|
|||||||
| not isLecturer = wFormToAForm $ pure . Just <$> requireAuthId
|
| not isLecturer = wFormToAForm $ pure . Just <$> requireAuthId
|
||||||
| otherwise = wFormToAForm $ do
|
| otherwise = wFormToAForm $ do
|
||||||
let correctors = E.from $ \user -> do
|
let correctors = E.from $ \user -> do
|
||||||
let isCorrector = E.exists . E.from $ \sheetCorrector ->
|
let isCorrector = E.exists . E.from $ \sheetCorrector ->
|
||||||
E.where_ $ sheetCorrector E.^. SheetCorrectorUser E.==. user E.^. UserId
|
E.where_ $ sheetCorrector E.^. SheetCorrectorUser E.==. user E.^. UserId
|
||||||
E.&&. sheetCorrector E.^. SheetCorrectorSheet E.==. E.val shId
|
E.&&. sheetCorrector E.^. SheetCorrectorSheet E.==. E.val shId
|
||||||
isLecturer' = E.exists . E.from $ \lecturer ->
|
isLecturer' = E.exists . E.from $ \lecturer ->
|
||||||
@ -151,7 +151,7 @@ postCorrectionR tid ssh csh shn cid = do
|
|||||||
|
|
||||||
getCorrectionUserR tid ssh csh shn cid = do
|
getCorrectionUserR tid ssh csh shn cid = do
|
||||||
|
|
||||||
|
|
||||||
sub <- decrypt cid
|
sub <- decrypt cid
|
||||||
|
|
||||||
results <- runDB $ correctionData tid ssh csh shn sub
|
results <- runDB $ correctionData tid ssh csh shn sub
|
||||||
|
|||||||
@ -104,9 +104,9 @@ makeSubmissionForm cid msmid uploadMode grouping isLecturer prefillUsers = ident
|
|||||||
submittorsForm' = maybeT submittorsForm $ do
|
submittorsForm' = maybeT submittorsForm $ do
|
||||||
restr <- MaybeT (maybeCurrentBearerRestrictions @Value) >>= hoistMaybe . preview (_Object . ix "submittors" . _Array)
|
restr <- MaybeT (maybeCurrentBearerRestrictions @Value) >>= hoistMaybe . preview (_Object . ix "submittors" . _Array)
|
||||||
let _Submittor = prism (either toJSON toJSON) $ \x -> first (const x) $ JSON.parseEither (\x' -> fmap Right (parseJSON x') <|> fmap Left (parseJSON x')) x
|
let _Submittor = prism (either toJSON toJSON) $ \x -> first (const x) $ JSON.parseEither (\x' -> fmap Right (parseJSON x') <|> fmap Left (parseJSON x')) x
|
||||||
submittors <- fmap (pure @FormResult @([Either UserEmail CryptoUUIDUser])) . forM (toList restr) $ hoistMaybe . preview _Submittor
|
submittors <- fmap (pure @FormResult @[Either UserEmail CryptoUUIDUser]) . forM (toList restr) $ hoistMaybe . preview _Submittor
|
||||||
fmap Set.fromList <$> forMOf (traverse . traverse . _Right) submittors decrypt
|
fmap Set.fromList <$> forMOf (traverse . traverse . _Right) submittors decrypt
|
||||||
|
|
||||||
|
|
||||||
submittorsForm
|
submittorsForm
|
||||||
| isLecturer = do -- Form is being used by lecturer; allow Everything™
|
| isLecturer = do -- Form is being used by lecturer; allow Everything™
|
||||||
@ -165,7 +165,7 @@ makeSubmissionForm cid msmid uploadMode grouping isLecturer prefillUsers = ident
|
|||||||
guard $ Map.size dat > 1
|
guard $ Map.size dat > 1
|
||||||
|
|
||||||
-- User may drop from submission only if it already exists; no directly creating submissions for other people
|
-- User may drop from submission only if it already exists; no directly creating submissions for other people
|
||||||
guard $ maybe True (/= Right uid) (dat !? delPos) || isJust msmid
|
guard $ Just (Right uid) /= dat !? delPos || isJust msmid
|
||||||
|
|
||||||
miDeleteList dat delPos
|
miDeleteList dat delPos
|
||||||
|
|
||||||
@ -304,7 +304,7 @@ submissionHelper tid ssh csh shn mcid = do
|
|||||||
return (userName, submissionEdit E.^. SubmissionEditTime)
|
return (userName, submissionEdit E.^. SubmissionEditTime)
|
||||||
forM raw $ \(E.Value name, E.Value time) -> (name, ) <$> formatTime SelFormatDateTime time
|
forM raw $ \(E.Value name, E.Value time) -> (name, ) <$> formatTime SelFormatDateTime time
|
||||||
|
|
||||||
corrector <- fmap join $ traverse getEntity submissionRatingBy
|
corrector <- join <$> traverse getEntity submissionRatingBy
|
||||||
|
|
||||||
return (csheet,buddies,lastEdits,maySubmit,isLecturer,isOwner,Just sub,corrector)
|
return (csheet,buddies,lastEdits,maySubmit,isLecturer,isOwner,Just sub,corrector)
|
||||||
|
|
||||||
@ -336,9 +336,9 @@ submissionHelper tid ssh csh shn mcid = do
|
|||||||
when ( is _Nothing muid
|
when ( is _Nothing muid
|
||||||
&& is _Nothing msubmission
|
&& is _Nothing msubmission
|
||||||
&& not isLecturer
|
&& not isLecturer
|
||||||
)
|
)
|
||||||
notAuthenticated
|
notAuthenticated
|
||||||
|
|
||||||
-- Determine old submission users
|
-- Determine old submission users
|
||||||
subUsersOld <- if
|
subUsersOld <- if
|
||||||
| Just smid <- msmid -> Set.union
|
| Just smid <- msmid -> Set.union
|
||||||
@ -411,7 +411,7 @@ submissionHelper tid ssh csh shn mcid = do
|
|||||||
}
|
}
|
||||||
audit $ TransactionSubmissionEdit sid shid
|
audit $ TransactionSubmissionEdit sid shid
|
||||||
return sid
|
return sid
|
||||||
|
|
||||||
-- Determine new submission users
|
-- Determine new submission users
|
||||||
subUsers <- if
|
subUsers <- if
|
||||||
| isLecturer -> return adhocMembers
|
| isLecturer -> return adhocMembers
|
||||||
@ -461,7 +461,7 @@ submissionHelper tid ssh csh shn mcid = do
|
|||||||
audit $ TransactionSubmissionUserDelete smid subUid
|
audit $ TransactionSubmissionUserDelete smid subUid
|
||||||
unless (Just subUid == muid) $
|
unless (Just subUid == muid) $
|
||||||
queueDBJob . JobQueueNotification $ NotificationSubmissionUserDeleted subUid shid smid
|
queueDBJob . JobQueueNotification $ NotificationSubmissionUserDeleted subUid shid smid
|
||||||
|
|
||||||
addMessageI Success $ if | Nothing <- msmid -> MsgSubmissionCreated
|
addMessageI Success $ if | Nothing <- msmid -> MsgSubmissionCreated
|
||||||
| otherwise -> MsgSubmissionUpdated
|
| otherwise -> MsgSubmissionUpdated
|
||||||
return smid
|
return smid
|
||||||
@ -558,7 +558,7 @@ submissionHelper tid ssh csh shn mcid = do
|
|||||||
courseSchool = ssh
|
courseSchool = ssh
|
||||||
courseShorthand = csh
|
courseShorthand = csh
|
||||||
in $(widgetFile "correction-user")
|
in $(widgetFile "correction-user")
|
||||||
|
|
||||||
|
|
||||||
defaultLayout $ do
|
defaultLayout $ do
|
||||||
setTitleI $ MsgSubmissionEditHead tid ssh csh shn
|
setTitleI $ MsgSubmissionEditHead tid ssh csh shn
|
||||||
|
|||||||
@ -122,7 +122,7 @@ colSelect :: forall act h. (Semigroup act, Monoid act, Headedness h) => Colonnad
|
|||||||
colSelect = dbSelect (_1 . applying _2) id $ \DBRow{ dbrOutput=(_, _, _, _, _, _, cid, _) } -> return cid
|
colSelect = dbSelect (_1 . applying _2) id $ \DBRow{ dbrOutput=(_, _, _, _, _, _, cid, _) } -> return cid
|
||||||
|
|
||||||
colSubmittors :: IsDBTable m a => Colonnade Sortable CorrectionTableData (DBCell m a)
|
colSubmittors :: IsDBTable m a => Colonnade Sortable CorrectionTableData (DBCell m a)
|
||||||
colSubmittors = sortable (Just "submittors") (i18nCell MsgSubmissionUsers) $ \DBRow{ dbrOutput=(_, Entity _ Sheet{..}, course, _, _, users, _, hasAccess) } ->
|
colSubmittors = sortable (Just "submittors") (i18nCell MsgSubmissionUsers) $ \DBRow{ dbrOutput=(_, _, course, _, _, users, _, hasAccess) } ->
|
||||||
let
|
let
|
||||||
csh = course ^. _2
|
csh = course ^. _2
|
||||||
tid = course ^. _3
|
tid = course ^. _3
|
||||||
@ -136,8 +136,8 @@ colSubmittors = sortable (Just "submittors") (i18nCell MsgSubmissionUsers) $ \DB
|
|||||||
| otherwise -> mempty
|
| otherwise -> mempty
|
||||||
|
|
||||||
colSMatrikel :: IsDBTable m a => Colonnade Sortable CorrectionTableData (DBCell m a)
|
colSMatrikel :: IsDBTable m a => Colonnade Sortable CorrectionTableData (DBCell m a)
|
||||||
colSMatrikel = sortable (Just "submittors-matriculation") (i18nCell MsgMatrikelNr) $ \DBRow{ dbrOutput=(_, Entity _ Sheet{..}, (_, csh, tid, ssh), _, _, users, _, hasAccess) } ->
|
colSMatrikel = sortable (Just "submittors-matriculation") (i18nCell MsgMatrikelNr) $ \DBRow{ dbrOutput=(_, _, (_, csh, tid, ssh), _, _, users, _, hasAccess) } ->
|
||||||
let protoCell = listCell (Map.toList $ Map.mapMaybe (\x@(User{..}, _, _) -> (x,) <$> assertM (not . null) userMatrikelnummer) users) $ \(userId, ((User{..}, _, _), matr)) -> anchorCellCM $cacheIdentHere (CourseR tid ssh csh . CUserR <$> encrypt userId) matr
|
let protoCell = listCell (Map.toList $ Map.mapMaybe (\x@(User{userMatrikelnummer}, _, _) -> (x,) <$> assertM (not . null) userMatrikelnummer) users) $ \(userId, (_, matr)) -> anchorCellCM $cacheIdentHere (CourseR tid ssh csh . CUserR <$> encrypt userId) matr
|
||||||
in if | hasAccess -> protoCell & cellAttrs <>~ [("class", "list--inline list--comma-separated")]
|
in if | hasAccess -> protoCell & cellAttrs <>~ [("class", "list--inline list--comma-separated")]
|
||||||
| otherwise -> mempty
|
| otherwise -> mempty
|
||||||
|
|
||||||
@ -193,7 +193,7 @@ colPointsField :: Colonnade Sortable CorrectionTableData (DBCell _ (FormResult (
|
|||||||
colPointsField = sortable (Just "rating") (i18nCell MsgColumnRatingPoints) $ formCell id
|
colPointsField = sortable (Just "rating") (i18nCell MsgColumnRatingPoints) $ formCell id
|
||||||
(\DBRow{ dbrOutput=(Entity subId _, _, _, _, _, _, _, _) } -> return subId)
|
(\DBRow{ dbrOutput=(Entity subId _, _, _, _, _, _, _, _) } -> return subId)
|
||||||
(\DBRow{ dbrOutput=(Entity _ Submission{..}, Entity _ Sheet{..}, _, _, _, _, _, _) } mkUnique -> case sheetType of
|
(\DBRow{ dbrOutput=(Entity _ Submission{..}, Entity _ Sheet{..}, _, _, _, _, _, _) } mkUnique -> case sheetType of
|
||||||
NotGraded -> over (_1.mapped) (_2 .~) <$> pure (FormSuccess Nothing, mempty)
|
NotGraded -> pure $ over (_1.mapped) (_2 .~) (FormSuccess Nothing, mempty)
|
||||||
_other -> over (_1.mapped) (_2 .~) . over _2 fvWidget <$> mopt (pointsFieldMax $ preview (_grading . _maxPoints) sheetType) (fsUniq mkUnique "points") (Just submissionRatingPoints)
|
_other -> over (_1.mapped) (_2 .~) . over _2 fvWidget <$> mopt (pointsFieldMax $ preview (_grading . _maxPoints) sheetType) (fsUniq mkUnique "points") (Just submissionRatingPoints)
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -201,7 +201,7 @@ colMaxPointsField :: _ => Colonnade Sortable CorrectionTableData (DBCell m (Form
|
|||||||
colMaxPointsField = sortable (Just "sheet-type") (i18nCell MsgSheetType) $ i18nCell . (\DBRow{ dbrOutput=(_, Entity _ Sheet{sheetType}, _, _, _, _, _, _) } -> sheetType)
|
colMaxPointsField = sortable (Just "sheet-type") (i18nCell MsgSheetType) $ i18nCell . (\DBRow{ dbrOutput=(_, Entity _ Sheet{sheetType}, _, _, _, _, _, _) } -> sheetType)
|
||||||
|
|
||||||
colCommentField :: Colonnade Sortable CorrectionTableData (DBCell _ (FormResult (DBFormResult SubmissionId (a, b, Maybe Text) CorrectionTableData)))
|
colCommentField :: Colonnade Sortable CorrectionTableData (DBCell _ (FormResult (DBFormResult SubmissionId (a, b, Maybe Text) CorrectionTableData)))
|
||||||
colCommentField = sortable (Just "comment") (i18nCell MsgRatingComment) $ fmap (cellAttrs <>~ [("style","width:60%")]) $ formCell id
|
colCommentField = sortable (Just "comment") (i18nCell MsgRatingComment) $ (cellAttrs <>~ [("style","width:60%")]) <$> formCell id
|
||||||
(\DBRow{ dbrOutput=(Entity subId _, _, _, _, _, _, _, _) } -> return subId)
|
(\DBRow{ dbrOutput=(Entity subId _, _, _, _, _, _, _, _) } -> return subId)
|
||||||
(\DBRow{ dbrOutput=(Entity _ Submission{..}, _, _, _, _, _, _, _) } mkUnique -> over (_1.mapped) ((_3 .~) . assertM (not . null) . fmap (Text.strip . unTextarea)) . over _2 fvWidget <$> mopt textareaField (fsUniq mkUnique "comment") (Just $ Textarea <$> submissionRatingComment))
|
(\DBRow{ dbrOutput=(Entity _ Submission{..}, _, _, _, _, _, _, _) } mkUnique -> over (_1.mapped) ((_3 .~) . assertM (not . null) . fmap (Text.strip . unTextarea)) . over _2 fvWidget <$> mopt textareaField (fsUniq mkUnique "comment") (Just $ Textarea <$> submissionRatingComment))
|
||||||
|
|
||||||
@ -398,11 +398,11 @@ makeCorrectionsTable whereClause dbtColonnade dbtFilterUI psValidator dbtParams
|
|||||||
, FilterProjected $ \(DBRow{..} :: CorrectionTableData) (criteria :: Set Text) ->
|
, FilterProjected $ \(DBRow{..} :: CorrectionTableData) (criteria :: Set Text) ->
|
||||||
let cid = map CI.mk . unpack . toPathPiece $ dbrOutput ^. _7
|
let cid = map CI.mk . unpack . toPathPiece $ dbrOutput ^. _7
|
||||||
criteria' = map CI.mk . unpack <$> Set.toList criteria
|
criteria' = map CI.mk . unpack <$> Set.toList criteria
|
||||||
in any (\c -> c `isInfixOf` cid) criteria'
|
in any (`isInfixOf` cid) criteria'
|
||||||
)
|
)
|
||||||
]
|
]
|
||||||
, dbtFilterUI = fromMaybe mempty dbtFilterUI
|
, dbtFilterUI = fromMaybe mempty dbtFilterUI
|
||||||
, dbtStyle = def { dbsFilterLayout = maybe (\_ _ _ -> id) (\_ -> defaultDBSFilterLayout) dbtFilterUI }
|
, dbtStyle = def { dbsFilterLayout = maybe (\_ _ _ -> id) (const defaultDBSFilterLayout) dbtFilterUI }
|
||||||
, dbtParams
|
, dbtParams
|
||||||
, dbtIdent = "corrections" :: Text
|
, dbtIdent = "corrections" :: Text
|
||||||
, dbtCsvEncode = noCsvEncode
|
, dbtCsvEncode = noCsvEncode
|
||||||
@ -465,8 +465,8 @@ correctionsR' whereClause displayColumns dbtFilterUI psValidator actions = do
|
|||||||
-- let statistics = gradeSummaryWidget MsgSubmissionGradingSummaryTitle gradingSummary
|
-- let statistics = gradeSummaryWidget MsgSubmissionGradingSummaryTitle gradingSummary
|
||||||
-- return (tableRes, statistics)
|
-- return (tableRes, statistics)
|
||||||
|
|
||||||
let actionRes = actionRes' & mapped._2 %~ Map.keysSet . Map.filter id . getDBFormResult (const False)
|
let actionRes = actionRes' <&> _2 %~ Map.keysSet . Map.filter id . getDBFormResult (const False)
|
||||||
& mapped._1 %~ fromMaybe (error "By consctruction the form should always return an action") . getLast
|
<&> _1 %~ fromMaybe (error "By consctruction the form should always return an action") . getLast
|
||||||
auditAllSubEdit = mapM_ $ \sId -> getJust sId >>= \sub -> audit $ TransactionSubmissionEdit sId $ sub ^. _submissionSheet
|
auditAllSubEdit = mapM_ $ \sId -> getJust sId >>= \sub -> audit $ TransactionSubmissionEdit sId $ sub ^. _submissionSheet
|
||||||
|
|
||||||
formResult actionRes $ \case
|
formResult actionRes $ \case
|
||||||
@ -610,7 +610,7 @@ assignAction selId = ( CorrSetCorrector
|
|||||||
|
|
||||||
E.where_ $ either (\cId -> course E.^. CourseId E.==. E.val cId) (\shId -> sheet E.^. SheetId E.==. E.val shId) selId
|
E.where_ $ either (\cId -> course E.^. CourseId E.==. E.val cId) (\shId -> sheet E.^. SheetId E.==. E.val shId) selId
|
||||||
|
|
||||||
E.orderBy $ [E.asc $ user E.^. UserSurname, E.asc $ user E.^. UserDisplayName]
|
E.orderBy [E.asc $ user E.^. UserSurname, E.asc $ user E.^. UserDisplayName]
|
||||||
|
|
||||||
E.distinct $ return user
|
E.distinct $ return user
|
||||||
|
|
||||||
|
|||||||
@ -15,7 +15,7 @@ import Text.Hamlet (ihamlet)
|
|||||||
|
|
||||||
import qualified Data.HashSet as HashSet
|
import qualified Data.HashSet as HashSet
|
||||||
|
|
||||||
|
|
||||||
instance IsInvitableJunction SubmissionUser where
|
instance IsInvitableJunction SubmissionUser where
|
||||||
type InvitationFor SubmissionUser = Submission
|
type InvitationFor SubmissionUser = Submission
|
||||||
data InvitableJunction SubmissionUser = JunctionSubmissionUser
|
data InvitableJunction SubmissionUser = JunctionSubmissionUser
|
||||||
|
|||||||
@ -31,7 +31,7 @@ explainSubmissionDoneMode SubmissionDoneNever = return $(i18nWidgetFile "submis
|
|||||||
explainSubmissionDoneMode SubmissionDoneAlways = return $(i18nWidgetFile "submission-done-tip/always")
|
explainSubmissionDoneMode SubmissionDoneAlways = return $(i18nWidgetFile "submission-done-tip/always")
|
||||||
explainSubmissionDoneMode SubmissionDoneByFile = return $(i18nWidgetFile "submission-done-tip/by-file")
|
explainSubmissionDoneMode SubmissionDoneByFile = return $(i18nWidgetFile "submission-done-tip/by-file")
|
||||||
|
|
||||||
|
|
||||||
getCorrectionsUploadR, postCorrectionsUploadR :: Handler Html
|
getCorrectionsUploadR, postCorrectionsUploadR :: Handler Html
|
||||||
getCorrectionsUploadR = postCorrectionsUploadR
|
getCorrectionsUploadR = postCorrectionsUploadR
|
||||||
postCorrectionsUploadR = do
|
postCorrectionsUploadR = do
|
||||||
|
|||||||
@ -57,9 +57,8 @@ postMessageR cID = do
|
|||||||
runFormPost . identifyForm (FIDSystemMessageModifyTranslation $ ciphertext cID') . renderAForm FormStandard
|
runFormPost . identifyForm (FIDSystemMessageModifyTranslation $ ciphertext cID') . renderAForm FormStandard
|
||||||
$ (,)
|
$ (,)
|
||||||
<$> fmap (Entity tId)
|
<$> fmap (Entity tId)
|
||||||
( SystemMessageTranslation
|
( SystemMessageTranslation systemMessageTranslationMessage
|
||||||
<$> pure systemMessageTranslationMessage
|
<$> areq (langField False) (fslpI MsgSystemMessageLanguage (mr MsgRFC1766)) (Just systemMessageTranslationLanguage)
|
||||||
<*> areq (langField False) (fslpI MsgSystemMessageLanguage (mr MsgRFC1766)) (Just systemMessageTranslationLanguage)
|
|
||||||
<*> areq htmlField (fslI MsgSystemMessageContent) (Just systemMessageTranslationContent)
|
<*> areq htmlField (fslI MsgSystemMessageContent) (Just systemMessageTranslationContent)
|
||||||
<*> aopt htmlField (fslI MsgSystemMessageSummary) (Just systemMessageTranslationSummary)
|
<*> aopt htmlField (fslI MsgSystemMessageSummary) (Just systemMessageTranslationSummary)
|
||||||
)
|
)
|
||||||
@ -71,9 +70,8 @@ postMessageR cID = do
|
|||||||
& filter (\l -> none (`langMatches` l) $ Map.keys ts')
|
& filter (\l -> none (`langMatches` l) $ Map.keys ts')
|
||||||
|
|
||||||
((addTransRes, addTransView), addTransEnctype) <- runFormPost . identifyForm FIDSystemMessageAddTranslation . renderAForm FormStandard
|
((addTransRes, addTransView), addTransEnctype) <- runFormPost . identifyForm FIDSystemMessageAddTranslation . renderAForm FormStandard
|
||||||
$ SystemMessageTranslation
|
$ SystemMessageTranslation smId
|
||||||
<$> pure smId
|
<$> areq (langField False) (fslpI MsgSystemMessageLanguage (mr MsgRFC1766)) (listToMaybe nextLang)
|
||||||
<*> areq (langField False) (fslpI MsgSystemMessageLanguage (mr MsgRFC1766)) (listToMaybe nextLang)
|
|
||||||
<*> areq htmlField (fslI MsgSystemMessageContent) Nothing
|
<*> areq htmlField (fslI MsgSystemMessageContent) Nothing
|
||||||
<*> aopt htmlField (fslI MsgSystemMessageSummary) Nothing
|
<*> aopt htmlField (fslI MsgSystemMessageSummary) Nothing
|
||||||
|
|
||||||
|
|||||||
@ -44,13 +44,13 @@ guessDay tid@TermIdentifier{ year, season = Winter } TermDayLectureStart
|
|||||||
guessDay tid@TermIdentifier{ year, season = Winter } TermDayLectureEnd
|
guessDay tid@TermIdentifier{ year, season = Winter } TermDayLectureEnd
|
||||||
= fromWeekDate (succ year) ((wWeekStart + 21) `div` bool 53 54 longYear) 5
|
= fromWeekDate (succ year) ((wWeekStart + 21) `div` bool 53 54 longYear) 5
|
||||||
where longYear = is _Just $ fromWeekDateValid year 53 1
|
where longYear = is _Just $ fromWeekDateValid year 53 1
|
||||||
(_, wWeekStart, _) = toWeekDate $ guessDay tid TermDayStart
|
(_, wWeekStart, _) = toWeekDate $ guessDay tid TermDayStart
|
||||||
guessDay tid@TermIdentifier{ year, season = Summer } TermDayLectureStart
|
guessDay tid@TermIdentifier{ year, season = Summer } TermDayLectureStart
|
||||||
= fromWeekDate year (wWeekStart + 2) 1
|
= fromWeekDate year (wWeekStart + 2) 1
|
||||||
where (_, wWeekStart, _) = toWeekDate $ guessDay tid TermDayStart
|
where (_, wWeekStart, _) = toWeekDate $ guessDay tid TermDayStart
|
||||||
guessDay tid@TermIdentifier{ year, season = Summer } TermDayLectureEnd
|
guessDay tid@TermIdentifier{ year, season = Summer } TermDayLectureEnd
|
||||||
= fromWeekDate year (wWeekStart + 17) 5
|
= fromWeekDate year (wWeekStart + 17) 5
|
||||||
where (_, wWeekStart, _) = toWeekDate $ guessDay tid TermDayStart
|
where (_, wWeekStart, _) = toWeekDate $ guessDay tid TermDayStart
|
||||||
|
|
||||||
|
|
||||||
validateTerm :: (MonadHandler m, HandlerSite m ~ UniWorX)
|
validateTerm :: (MonadHandler m, HandlerSite m ~ UniWorX)
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user