feat: reduce number of study features for courses
This commit is contained in:
parent
f44f150747
commit
51a98f0670
@ -879,6 +879,8 @@ SubmissionReplace: Abgabe ersetzen
|
|||||||
SubmissionCreated: Abgabe erfolgreich angelegt
|
SubmissionCreated: Abgabe erfolgreich angelegt
|
||||||
SubmissionUpdated: Abgabe erfolgreich ersetzt
|
SubmissionUpdated: Abgabe erfolgreich ersetzt
|
||||||
|
|
||||||
|
ColumnStudyFeatures: Studiendaten
|
||||||
|
|
||||||
AdminFeaturesHeading: Studiengänge
|
AdminFeaturesHeading: Studiengänge
|
||||||
StudyTerms: Studiengänge
|
StudyTerms: Studiengänge
|
||||||
StudyTerm: Studiengang
|
StudyTerm: Studiengang
|
||||||
|
|||||||
@ -21,17 +21,18 @@ module Database.Esqueleto.Utils
|
|||||||
, maybe, maybeEq, unsafeCoalesce
|
, maybe, maybeEq, unsafeCoalesce
|
||||||
, bool
|
, bool
|
||||||
, max, min
|
, max, min
|
||||||
|
, abs
|
||||||
, SqlProject(..)
|
, SqlProject(..)
|
||||||
, (->.)
|
, (->.)
|
||||||
, fromSqlKey
|
, fromSqlKey
|
||||||
, selectCountRows
|
, selectCountRows
|
||||||
, selectMaybe
|
, selectMaybe
|
||||||
, day
|
, day, diffDays
|
||||||
, module Database.Esqueleto.Utils.TH
|
, module Database.Esqueleto.Utils.TH
|
||||||
) where
|
) where
|
||||||
|
|
||||||
|
|
||||||
import ClassyPrelude.Yesod hiding (isInfixOf, any, all, or, and, isJust, maybe, bool, max, min)
|
import ClassyPrelude.Yesod hiding (isInfixOf, any, all, or, and, isJust, maybe, bool, max, min, abs)
|
||||||
import Data.Universe
|
import Data.Universe
|
||||||
import qualified Data.Set as Set
|
import qualified Data.Set as Set
|
||||||
import qualified Data.List as List
|
import qualified Data.List as List
|
||||||
@ -290,6 +291,11 @@ max, min :: PersistField a
|
|||||||
max a b = bool a b $ b E.>. a
|
max a b = bool a b $ b E.>. a
|
||||||
min a b = bool a b $ b E.<. a
|
min a b = bool a b $ b E.<. a
|
||||||
|
|
||||||
|
abs :: (PersistField a, Num a)
|
||||||
|
=> E.SqlExpr (E.Value a)
|
||||||
|
-> E.SqlExpr (E.Value a)
|
||||||
|
abs x = bool (E.val 0 E.-. x) x $ x E.>. E.val 0
|
||||||
|
|
||||||
unsafeCoalesce :: E.PersistField a => [E.SqlExpr (E.Value (Maybe a))] -> E.SqlExpr (E.Value a)
|
unsafeCoalesce :: E.PersistField a => [E.SqlExpr (E.Value (Maybe a))] -> E.SqlExpr (E.Value a)
|
||||||
unsafeCoalesce = E.veryUnsafeCoerceSqlExprValue . E.coalesce
|
unsafeCoalesce = E.veryUnsafeCoerceSqlExprValue . E.coalesce
|
||||||
|
|
||||||
@ -330,3 +336,9 @@ selectMaybe = fmap listToMaybe . E.select . (<* E.limit 1)
|
|||||||
|
|
||||||
day :: E.SqlExpr (E.Value UTCTime) -> E.SqlExpr (E.Value Day)
|
day :: E.SqlExpr (E.Value UTCTime) -> E.SqlExpr (E.Value Day)
|
||||||
day = E.unsafeSqlCastAs "date"
|
day = E.unsafeSqlCastAs "date"
|
||||||
|
|
||||||
|
infixl 6 `diffDays`
|
||||||
|
|
||||||
|
diffDays :: E.SqlExpr (E.Value Day) -> E.SqlExpr (E.Value Day) -> E.SqlExpr (E.Value Int)
|
||||||
|
-- ^ PostgreSQL is weird.
|
||||||
|
diffDays a b = E.veryUnsafeCoerceSqlExprValue $ a E.-. b
|
||||||
|
|||||||
@ -95,10 +95,10 @@ courseUserProfileSection (Entity cid Course{..}) (Entity uid User{ userShowSex =
|
|||||||
|
|
||||||
(mRegistration, studies) <- lift . runDB $ do
|
(mRegistration, studies) <- lift . runDB $ do
|
||||||
registration <- fmap (assertM . has $ _entityVal . _courseParticipantState . _CourseParticipantActive) . getBy $ UniqueParticipant uid cid
|
registration <- fmap (assertM . has $ _entityVal . _courseParticipantState . _CourseParticipantActive) . getBy $ UniqueParticipant uid cid
|
||||||
studies <- E.select $ E.from $ \(course `E.InnerJoin` studydegree `E.InnerJoin` studyfeat `E.InnerJoin` studyterms) -> do
|
studies <- E.select $ E.from $ \(course `E.InnerJoin` studyfeat `E.InnerJoin` studydegree `E.InnerJoin` studyterms) -> do
|
||||||
E.on $ isCourseStudyFeature course studyfeat
|
|
||||||
E.on $ studyfeat E.^. StudyFeaturesField E.==. studyterms E.^. StudyTermsId
|
E.on $ studyfeat E.^. StudyFeaturesField E.==. studyterms E.^. StudyTermsId
|
||||||
E.on $ studyfeat E.^. StudyFeaturesDegree E.==. studydegree E.^. StudyDegreeId
|
E.on $ studyfeat E.^. StudyFeaturesDegree E.==. studydegree E.^. StudyDegreeId
|
||||||
|
E.on $ isCourseStudyFeature course studyfeat
|
||||||
E.where_ $ studyfeat E.^. StudyFeaturesUser E.==. E.val uid
|
E.where_ $ studyfeat E.^. StudyFeaturesUser E.==. E.val uid
|
||||||
E.where_ $ course E.^. CourseId E.==. E.val cid
|
E.where_ $ course E.^. CourseId E.==. E.val cid
|
||||||
return (studyfeat, studydegree, studyterms)
|
return (studyfeat, studydegree, studyterms)
|
||||||
|
|||||||
@ -524,6 +524,7 @@ postCUsersR tid ssh csh = do
|
|||||||
, guardOn showSex . cap' $ colUserSex'
|
, guardOn showSex . cap' $ colUserSex'
|
||||||
, pure . cap' $ colUserEmail
|
, pure . cap' $ colUserEmail
|
||||||
, pure . cap' $ colUserMatriclenr
|
, pure . cap' $ colUserMatriclenr
|
||||||
|
, pure . cap' $ colStudyFeatures _userStudyFeatures
|
||||||
, guardOn hasSubmissionGroups $ cap' colUserSubmissionGroup
|
, guardOn hasSubmissionGroups $ cap' colUserSubmissionGroup
|
||||||
, guardOn hasTutorials . cap' $ colUserTutorials tid ssh csh
|
, guardOn hasTutorials . cap' $ colUserTutorials tid ssh csh
|
||||||
, guardOn hasExams . cap' $ colUserExams tid ssh csh
|
, guardOn hasExams . cap' $ colUserExams tid ssh csh
|
||||||
|
|||||||
@ -3,6 +3,7 @@ module Handler.Utils.StudyFeatures
|
|||||||
, UserTableStudyFeature(..)
|
, UserTableStudyFeature(..)
|
||||||
, _userTableField, _userTableDegree, _userTableSemester, _userTableFieldType
|
, _userTableField, _userTableDegree, _userTableSemester, _userTableFieldType
|
||||||
, UserTableStudyFeatures(..)
|
, UserTableStudyFeatures(..)
|
||||||
|
, _UserTableStudyFeatures
|
||||||
, isCourseStudyFeature, courseUserStudyFeatures
|
, isCourseStudyFeature, courseUserStudyFeatures
|
||||||
, isExternalExamStudyFeature, externalExamUserStudyFeatures
|
, isExternalExamStudyFeature, externalExamUserStudyFeatures
|
||||||
) where
|
) where
|
||||||
@ -42,6 +43,9 @@ newtype UserTableStudyFeatures = UserTableStudyFeatures (Set UserTableStudyFeatu
|
|||||||
deriving newtype (ToJSON, FromJSON)
|
deriving newtype (ToJSON, FromJSON)
|
||||||
makeWrapped ''UserTableStudyFeatures
|
makeWrapped ''UserTableStudyFeatures
|
||||||
|
|
||||||
|
_UserTableStudyFeatures :: Iso' UserTableStudyFeatures [UserTableStudyFeature]
|
||||||
|
_UserTableStudyFeatures = iso (sortBy userTableStudyFeatureSort . Set.toList . view _Wrapped) (UserTableStudyFeatures . Set.fromList)
|
||||||
|
|
||||||
instance Csv.ToField UserTableStudyFeature where
|
instance Csv.ToField UserTableStudyFeature where
|
||||||
toField UserTableStudyFeature{..} = encodeUtf8
|
toField UserTableStudyFeature{..} = encodeUtf8
|
||||||
[st|#{userTableField} #{userTableDegree} (#{userTableFieldType'} #{tshow userTableSemester})|]
|
[st|#{userTableField} #{userTableDegree} (#{userTableFieldType'} #{tshow userTableSemester})|]
|
||||||
@ -50,7 +54,7 @@ instance Csv.ToField UserTableStudyFeature where
|
|||||||
[] $ ShortStudyFieldType userTableFieldType
|
[] $ ShortStudyFieldType userTableFieldType
|
||||||
|
|
||||||
instance Csv.ToField UserTableStudyFeatures where
|
instance Csv.ToField UserTableStudyFeatures where
|
||||||
toField = ByteString.intercalate "; " . map Csv.toField . sortBy userTableStudyFeatureSort . Set.toList . view _Wrapped
|
toField = ByteString.intercalate "; " . map Csv.toField . view _UserTableStudyFeatures
|
||||||
|
|
||||||
userTableStudyFeatureSort :: UserTableStudyFeature
|
userTableStudyFeatureSort :: UserTableStudyFeature
|
||||||
-> UserTableStudyFeature
|
-> UserTableStudyFeature
|
||||||
@ -63,12 +67,33 @@ userTableStudyFeatureSort = mconcat
|
|||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
isRelevantStudyFeature :: PersistEntity record
|
||||||
|
=> EntityField record TermId
|
||||||
|
-> E.SqlExpr (Entity record)
|
||||||
|
-> E.SqlExpr (Entity StudyFeatures)
|
||||||
|
-> E.SqlExpr (E.Value Bool)
|
||||||
|
isRelevantStudyFeature termField record studyFeatures
|
||||||
|
= overlap studyFeatures E.>. E.val 0
|
||||||
|
E.&&. E.not_ (E.exists betterOverlap)
|
||||||
|
where termEnd = E.subSelectForeign record termField (E.^. TermEnd)
|
||||||
|
termStart = E.subSelectForeign record termField (E.^. TermStart)
|
||||||
|
|
||||||
|
overlap :: E.SqlExpr (Entity StudyFeatures) -> E.SqlExpr (E.Value Int)
|
||||||
|
overlap studyFeatures'
|
||||||
|
= E.min (E.day $ studyFeatures' E.^. StudyFeaturesLastObserved) termEnd
|
||||||
|
`E.diffDays` E.maybe termStart (E.max termStart . E.day) (studyFeatures' E.^. StudyFeaturesFirstObserved)
|
||||||
|
|
||||||
|
betterOverlap = E.from $ \studyFeatures' -> do
|
||||||
|
E.where_ $ studyFeatures' E.^. StudyFeaturesUser E.==. studyFeatures E.^. StudyFeaturesUser
|
||||||
|
E.&&. studyFeatures' E.^. StudyFeaturesDegree E.==. studyFeatures E.^. StudyFeaturesDegree
|
||||||
|
E.&&. studyFeatures' E.^. StudyFeaturesField E.==. studyFeatures E.^. StudyFeaturesField
|
||||||
|
E.&&. studyFeatures' E.^. StudyFeaturesSuperField `E.maybeEq` studyFeatures E.^. StudyFeaturesSuperField
|
||||||
|
E.&&. studyFeatures' E.^. StudyFeaturesType E.==. studyFeatures E.^. StudyFeaturesType
|
||||||
|
E.where_ $ E.abs (studyFeatures' E.^. StudyFeaturesSemester E.-. studyFeatures E.^. StudyFeaturesSemester) E.==. E.val 1
|
||||||
|
E.&&. overlap studyFeatures' E.>. overlap studyFeatures
|
||||||
|
|
||||||
isCourseStudyFeature :: E.SqlExpr (Entity Course) -> E.SqlExpr (Entity StudyFeatures) -> E.SqlExpr (E.Value Bool)
|
isCourseStudyFeature :: E.SqlExpr (Entity Course) -> E.SqlExpr (Entity StudyFeatures) -> E.SqlExpr (E.Value Bool)
|
||||||
isCourseStudyFeature course studyFeatures
|
isCourseStudyFeature = isRelevantStudyFeature CourseTerm
|
||||||
= E.maybe E.true ((E.<=. termEnd) . E.day) (studyFeatures E.^. StudyFeaturesFirstObserved)
|
|
||||||
E.&&. E.day (studyFeatures E.^. StudyFeaturesLastObserved) E.>=. termStart
|
|
||||||
where termEnd = E.subSelectForeign course CourseTerm (E.^. TermEnd)
|
|
||||||
termStart = E.subSelectForeign course CourseTerm (E.^. TermStart)
|
|
||||||
|
|
||||||
courseUserStudyFeatures :: MonadIO m => CourseId -> UserId -> SqlPersistT m UserTableStudyFeatures
|
courseUserStudyFeatures :: MonadIO m => CourseId -> UserId -> SqlPersistT m UserTableStudyFeatures
|
||||||
courseUserStudyFeatures cId uid = do
|
courseUserStudyFeatures cId uid = do
|
||||||
@ -88,11 +113,7 @@ courseUserStudyFeatures cId uid = do
|
|||||||
}
|
}
|
||||||
|
|
||||||
isExternalExamStudyFeature :: E.SqlExpr (Entity ExternalExam) -> E.SqlExpr (Entity StudyFeatures) -> E.SqlExpr (E.Value Bool)
|
isExternalExamStudyFeature :: E.SqlExpr (Entity ExternalExam) -> E.SqlExpr (Entity StudyFeatures) -> E.SqlExpr (E.Value Bool)
|
||||||
isExternalExamStudyFeature externalExam studyFeatures
|
isExternalExamStudyFeature = isRelevantStudyFeature ExternalExamTerm
|
||||||
= E.maybe E.true ((E.<=. termEnd) . E.day) (studyFeatures E.^. StudyFeaturesFirstObserved)
|
|
||||||
E.&&. E.day (studyFeatures E.^. StudyFeaturesLastObserved) E.>=. termStart
|
|
||||||
where termEnd = E.subSelectForeign externalExam ExternalExamTerm (E.^. TermEnd)
|
|
||||||
termStart = E.subSelectForeign externalExam ExternalExamTerm (E.^. TermStart)
|
|
||||||
|
|
||||||
externalExamUserStudyFeatures :: MonadIO m => ExternalExamId -> UserId -> SqlPersistT m UserTableStudyFeatures
|
externalExamUserStudyFeatures :: MonadIO m => ExternalExamId -> UserId -> SqlPersistT m UserTableStudyFeatures
|
||||||
externalExamUserStudyFeatures eeId uid = do
|
externalExamUserStudyFeatures eeId uid = do
|
||||||
|
|||||||
@ -24,6 +24,7 @@ import Handler.Utils.Table.Pagination
|
|||||||
import Handler.Utils.Form
|
import Handler.Utils.Form
|
||||||
import Handler.Utils.Widgets
|
import Handler.Utils.Widgets
|
||||||
import Handler.Utils.DateTime
|
import Handler.Utils.DateTime
|
||||||
|
import Handler.Utils.StudyFeatures
|
||||||
|
|
||||||
import qualified Data.CaseInsensitive as CI
|
import qualified Data.CaseInsensitive as CI
|
||||||
|
|
||||||
@ -778,6 +779,13 @@ fltrDegreeUI :: Maybe (Map FilterKey [Text]) -> AForm (YesodDB UniWorX) (Map Fil
|
|||||||
fltrDegreeUI mPrev =
|
fltrDegreeUI mPrev =
|
||||||
prismAForm (singletonFilter "degree") mPrev $ aopt textField (fslI MsgDegreeName)
|
prismAForm (singletonFilter "degree") mPrev $ aopt textField (fslI MsgDegreeName)
|
||||||
|
|
||||||
|
|
||||||
|
colStudyFeatures :: OpticColonnade UserTableStudyFeatures
|
||||||
|
colStudyFeatures resultFeatures = Colonnade.singleton (fromSortable header) body
|
||||||
|
where
|
||||||
|
header = Sortable Nothing (i18nCell MsgColumnStudyFeatures)
|
||||||
|
body = views (resultFeatures . _UserTableStudyFeatures) . flip listCell $ \UserTableStudyFeature{..} -> cell $(widgetFile "table/cell/user-study-feature")
|
||||||
|
|
||||||
-----------------
|
-----------------
|
||||||
-- Allocations --
|
-- Allocations --
|
||||||
-----------------
|
-----------------
|
||||||
|
|||||||
2
templates/table/cell/user-study-feature.hamlet
Normal file
2
templates/table/cell/user-study-feature.hamlet
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
$newline never
|
||||||
|
#{userTableField} #{userTableDegree} (_{userTableFieldType} #{userTableSemester})
|
||||||
Reference in New Issue
Block a user