feat(exams): show exam results
This commit is contained in:
parent
d5be5d61ee
commit
b8b308d608
@ -11,6 +11,7 @@ module Database.Esqueleto.Utils
|
|||||||
, mkContainsFilter, mkContainsFilterWith
|
, mkContainsFilter, mkContainsFilterWith
|
||||||
, mkExistsFilter
|
, mkExistsFilter
|
||||||
, anyFilter, allFilter
|
, anyFilter, allFilter
|
||||||
|
, orderByList
|
||||||
, orderByOrd, orderByEnum
|
, orderByOrd, orderByEnum
|
||||||
, lower, ciEq
|
, lower, ciEq
|
||||||
) where
|
) where
|
||||||
@ -167,12 +168,16 @@ allFilter fltrs needle criterias = F.foldr aux true fltrs
|
|||||||
aux fltr acc = fltr needle criterias E.&&. acc
|
aux fltr acc = fltr needle criterias E.&&. acc
|
||||||
|
|
||||||
|
|
||||||
|
orderByList :: PersistField a => [a] -> E.SqlExpr (E.Value a) -> E.SqlExpr (E.Value Int)
|
||||||
|
orderByList vals
|
||||||
|
= 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)
|
||||||
|
|
||||||
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 = let sortUni = zip [1..] $ List.sort universeF in -- memoize this, might not work due to polymorphism
|
orderByOrd = orderByList $ List.sort universeF
|
||||||
\x -> E.case_ [ (x E.==. E.val u, E.val i) | (i,u) <- sortUni ] (E.val (-1))
|
|
||||||
|
|
||||||
orderByEnum :: (Enum a, Finite a, PersistField a) => E.SqlExpr (E.Value a) -> E.SqlExpr (E.Value Int)
|
orderByEnum :: (Enum a, Finite a, PersistField a) => E.SqlExpr (E.Value a) -> E.SqlExpr (E.Value Int)
|
||||||
orderByEnum x = E.case_ [ (x E.==. E.val u, E.val $ fromEnum u) | u <- universeF ] (E.val (-1))
|
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)
|
||||||
|
|||||||
@ -334,6 +334,23 @@ instance RenderMessage UniWorX StudyDegreeTerm where
|
|||||||
instance RenderMessage UniWorX ExamGrade where
|
instance RenderMessage UniWorX ExamGrade where
|
||||||
renderMessage _ _ = pack . (showFixed False :: Deci -> String) . fromRational . review numberGrade
|
renderMessage _ _ = pack . (showFixed False :: Deci -> String) . fromRational . review numberGrade
|
||||||
|
|
||||||
|
instance RenderMessage UniWorX ExamPassed where
|
||||||
|
renderMessage foundation ls = \case
|
||||||
|
ExamPassed True -> mr MsgExamPassed
|
||||||
|
ExamPassed False -> mr MsgExamNotPassed
|
||||||
|
where
|
||||||
|
mr :: RenderMessage UniWorX msg => msg -> Text
|
||||||
|
mr = renderMessage foundation ls
|
||||||
|
|
||||||
|
instance RenderMessage UniWorX a => RenderMessage UniWorX (ExamResult' a) where
|
||||||
|
renderMessage foundation ls = \case
|
||||||
|
ExamAttended{..} -> mr examResult
|
||||||
|
ExamNoShow -> mr MsgExamResultNoShow
|
||||||
|
ExamVoided -> mr MsgExamResultVoided
|
||||||
|
where
|
||||||
|
mr :: RenderMessage UniWorX msg => msg -> Text
|
||||||
|
mr = renderMessage foundation ls
|
||||||
|
|
||||||
|
|
||||||
-- ToMessage instances for converting raw numbers to Text (no internationalization)
|
-- ToMessage instances for converting raw numbers to Text (no internationalization)
|
||||||
|
|
||||||
|
|||||||
@ -36,8 +36,8 @@ import Control.Arrow (Kleisli(..))
|
|||||||
import Database.Persist.Sql (deleteWhereCount, updateWhereCount)
|
import Database.Persist.Sql (deleteWhereCount, updateWhereCount)
|
||||||
|
|
||||||
|
|
||||||
type ExamUserTableExpr = (E.SqlExpr (Entity ExamRegistration) `E.InnerJoin` E.SqlExpr (Entity User)) `E.LeftOuterJoin` E.SqlExpr (Maybe (Entity ExamOccurrence)) `E.LeftOuterJoin` (E.SqlExpr (Maybe (Entity CourseParticipant)) `E.LeftOuterJoin` (E.SqlExpr (Maybe (Entity StudyFeatures)) `E.InnerJoin` E.SqlExpr (Maybe (Entity StudyDegree)) `E.InnerJoin` E.SqlExpr (Maybe (Entity StudyTerms))))
|
type ExamUserTableExpr = (E.SqlExpr (Entity ExamRegistration) `E.InnerJoin` E.SqlExpr (Entity User)) `E.LeftOuterJoin` E.SqlExpr (Maybe (Entity ExamOccurrence)) `E.LeftOuterJoin` (E.SqlExpr (Maybe (Entity CourseParticipant)) `E.LeftOuterJoin` (E.SqlExpr (Maybe (Entity StudyFeatures)) `E.InnerJoin` E.SqlExpr (Maybe (Entity StudyDegree)) `E.InnerJoin` E.SqlExpr (Maybe (Entity StudyTerms)))) `E.LeftOuterJoin` E.SqlExpr (Maybe (Entity ExamResult))
|
||||||
type ExamUserTableData = DBRow (Entity ExamRegistration, Entity User, Maybe (Entity ExamOccurrence), Maybe (Entity StudyFeatures), Maybe (Entity StudyDegree), Maybe (Entity StudyTerms))
|
type ExamUserTableData = DBRow (Entity ExamRegistration, Entity User, Maybe (Entity ExamOccurrence), Maybe (Entity StudyFeatures), Maybe (Entity StudyDegree), Maybe (Entity StudyTerms), Maybe (Entity ExamResult))
|
||||||
|
|
||||||
instance HasEntity ExamUserTableData User where
|
instance HasEntity ExamUserTableData User where
|
||||||
hasEntity = _dbrOutput . _2
|
hasEntity = _dbrOutput . _2
|
||||||
@ -49,22 +49,25 @@ _userTableOccurrence :: Lens' ExamUserTableData (Maybe (Entity ExamOccurrence))
|
|||||||
_userTableOccurrence = _dbrOutput . _3
|
_userTableOccurrence = _dbrOutput . _3
|
||||||
|
|
||||||
queryUser :: ExamUserTableExpr -> E.SqlExpr (Entity User)
|
queryUser :: ExamUserTableExpr -> E.SqlExpr (Entity User)
|
||||||
queryUser = $(sqlIJproj 2 2) . $(sqlLOJproj 3 1)
|
queryUser = $(sqlIJproj 2 2) . $(sqlLOJproj 4 1)
|
||||||
|
|
||||||
queryStudyFeatures :: ExamUserTableExpr -> E.SqlExpr (Maybe (Entity StudyFeatures))
|
queryStudyFeatures :: ExamUserTableExpr -> E.SqlExpr (Maybe (Entity StudyFeatures))
|
||||||
queryStudyFeatures = $(sqlIJproj 3 1) . $(sqlLOJproj 2 2) . $(sqlLOJproj 3 3)
|
queryStudyFeatures = $(sqlIJproj 3 1) . $(sqlLOJproj 2 2) . $(sqlLOJproj 4 3)
|
||||||
|
|
||||||
queryExamRegistration :: ExamUserTableExpr -> E.SqlExpr (Entity ExamRegistration)
|
queryExamRegistration :: ExamUserTableExpr -> E.SqlExpr (Entity ExamRegistration)
|
||||||
queryExamRegistration = $(sqlIJproj 2 1) . $(sqlLOJproj 3 1)
|
queryExamRegistration = $(sqlIJproj 2 1) . $(sqlLOJproj 4 1)
|
||||||
|
|
||||||
queryExamOccurrence :: ExamUserTableExpr -> E.SqlExpr (Maybe (Entity ExamOccurrence))
|
queryExamOccurrence :: ExamUserTableExpr -> E.SqlExpr (Maybe (Entity ExamOccurrence))
|
||||||
queryExamOccurrence = $(sqlLOJproj 3 2)
|
queryExamOccurrence = $(sqlLOJproj 4 2)
|
||||||
|
|
||||||
queryStudyDegree :: ExamUserTableExpr -> E.SqlExpr (Maybe (Entity StudyDegree))
|
queryStudyDegree :: ExamUserTableExpr -> E.SqlExpr (Maybe (Entity StudyDegree))
|
||||||
queryStudyDegree = $(sqlIJproj 3 2) . $(sqlLOJproj 2 2) . $(sqlLOJproj 3 3)
|
queryStudyDegree = $(sqlIJproj 3 2) . $(sqlLOJproj 2 2) . $(sqlLOJproj 4 3)
|
||||||
|
|
||||||
queryStudyField :: ExamUserTableExpr -> E.SqlExpr (Maybe (Entity StudyTerms))
|
queryStudyField :: ExamUserTableExpr -> E.SqlExpr (Maybe (Entity StudyTerms))
|
||||||
queryStudyField = $(sqlIJproj 3 3) . $(sqlLOJproj 2 2) . $(sqlLOJproj 3 3)
|
queryStudyField = $(sqlIJproj 3 3) . $(sqlLOJproj 2 2) . $(sqlLOJproj 4 3)
|
||||||
|
|
||||||
|
queryExamResult :: ExamUserTableExpr -> E.SqlExpr (Maybe (Entity ExamResult))
|
||||||
|
queryExamResult = $(sqlLOJproj 4 4)
|
||||||
|
|
||||||
resultExamRegistration :: Lens' ExamUserTableData (Entity ExamRegistration)
|
resultExamRegistration :: Lens' ExamUserTableData (Entity ExamRegistration)
|
||||||
resultExamRegistration = _dbrOutput . _1
|
resultExamRegistration = _dbrOutput . _1
|
||||||
@ -84,6 +87,9 @@ resultStudyField = _dbrOutput . _6 . _Just
|
|||||||
resultExamOccurrence :: Traversal' ExamUserTableData (Entity ExamOccurrence)
|
resultExamOccurrence :: Traversal' ExamUserTableData (Entity ExamOccurrence)
|
||||||
resultExamOccurrence = _dbrOutput . _3 . _Just
|
resultExamOccurrence = _dbrOutput . _3 . _Just
|
||||||
|
|
||||||
|
resultExamResult :: Traversal' ExamUserTableData (Entity ExamResult)
|
||||||
|
resultExamResult = _dbrOutput . _7 . _Just
|
||||||
|
|
||||||
data ExamUserTableCsv = ExamUserTableCsv
|
data ExamUserTableCsv = ExamUserTableCsv
|
||||||
{ csvEUserSurname :: Maybe Text
|
{ csvEUserSurname :: Maybe Text
|
||||||
, csvEUserName :: Maybe Text
|
, csvEUserName :: Maybe Text
|
||||||
@ -200,7 +206,9 @@ postEUsersR tid ssh csh examn = do
|
|||||||
let
|
let
|
||||||
examUsersDBTable = DBTable{..}
|
examUsersDBTable = DBTable{..}
|
||||||
where
|
where
|
||||||
dbtSQLQuery ((examRegistration `E.InnerJoin` user) `E.LeftOuterJoin` occurrence `E.LeftOuterJoin` (courseParticipant `E.LeftOuterJoin` (studyFeatures `E.InnerJoin` studyDegree `E.InnerJoin` studyField))) = do
|
dbtSQLQuery ((examRegistration `E.InnerJoin` user) `E.LeftOuterJoin` occurrence `E.LeftOuterJoin` (courseParticipant `E.LeftOuterJoin` (studyFeatures `E.InnerJoin` studyDegree `E.InnerJoin` studyField)) `E.LeftOuterJoin` examResult) = do
|
||||||
|
E.on $ examResult E.?. ExamResultUser E.==. E.just (user E.^. UserId)
|
||||||
|
E.&&. examResult E.?. ExamResultExam E.==. E.just (E.val eid)
|
||||||
E.on $ studyField E.?. StudyTermsId E.==. studyFeatures E.?. StudyFeaturesField
|
E.on $ studyField E.?. StudyTermsId E.==. studyFeatures E.?. StudyFeaturesField
|
||||||
E.on $ studyDegree E.?. StudyDegreeId E.==. studyFeatures E.?. StudyFeaturesDegree
|
E.on $ studyDegree E.?. StudyDegreeId E.==. studyFeatures E.?. StudyFeaturesDegree
|
||||||
E.on $ studyFeatures E.?. StudyFeaturesId E.==. E.joinV (courseParticipant E.?. CourseParticipantField)
|
E.on $ studyFeatures E.?. StudyFeaturesId E.==. E.joinV (courseParticipant E.?. CourseParticipantField)
|
||||||
@ -210,7 +218,7 @@ postEUsersR tid ssh csh examn = do
|
|||||||
E.&&. occurrence E.?. ExamOccurrenceId E.==. examRegistration E.^. ExamRegistrationOccurrence
|
E.&&. occurrence E.?. ExamOccurrenceId E.==. examRegistration E.^. ExamRegistrationOccurrence
|
||||||
E.on $ examRegistration E.^. ExamRegistrationUser E.==. user E.^. UserId
|
E.on $ examRegistration E.^. ExamRegistrationUser E.==. user E.^. UserId
|
||||||
E.where_ $ examRegistration E.^. ExamRegistrationExam E.==. E.val eid
|
E.where_ $ examRegistration E.^. ExamRegistrationExam E.==. E.val eid
|
||||||
return (examRegistration, user, occurrence, studyFeatures, studyDegree, studyField)
|
return (examRegistration, user, occurrence, studyFeatures, studyDegree, studyField, examResult)
|
||||||
dbtRowKey = queryExamRegistration >>> (E.^. ExamRegistrationId)
|
dbtRowKey = queryExamRegistration >>> (E.^. ExamRegistrationId)
|
||||||
dbtProj = return
|
dbtProj = return
|
||||||
dbtColonnade = mconcat $ catMaybes
|
dbtColonnade = mconcat $ catMaybes
|
||||||
@ -229,6 +237,8 @@ postEUsersR tid ssh csh examn = do
|
|||||||
SheetGradeSummary{achievedPoints} <- examBonusAchieved uid bonus
|
SheetGradeSummary{achievedPoints} <- examBonusAchieved uid bonus
|
||||||
SheetGradeSummary{sumSheetsPoints} <- examBonusPossible uid bonus
|
SheetGradeSummary{sumSheetsPoints} <- examBonusPossible uid bonus
|
||||||
return $ propCell (getSum achievedPoints) (getSum sumSheetsPoints)
|
return $ propCell (getSum achievedPoints) (getSum sumSheetsPoints)
|
||||||
|
, guardOn examShowGrades $ sortable (Just "result") (i18nCell MsgExamResult) $ maybe mempty i18nCell . preview (resultExamResult . _entityVal . _examResultResult)
|
||||||
|
, guardOn (not examShowGrades) $ sortable (Just "result-bool") (i18nCell MsgExamResult) $ maybe mempty i18nCell . preview (resultExamResult . _entityVal . _examResultResult . to (over _examResult $ view passingGrade))
|
||||||
]
|
]
|
||||||
dbtSorting = Map.fromList
|
dbtSorting = Map.fromList
|
||||||
[ sortUserNameLink queryUser
|
[ sortUserNameLink queryUser
|
||||||
@ -239,6 +249,8 @@ postEUsersR tid ssh csh examn = do
|
|||||||
, sortDegreeShort queryStudyDegree
|
, sortDegreeShort queryStudyDegree
|
||||||
, sortFeaturesSemester queryStudyFeatures
|
, sortFeaturesSemester queryStudyFeatures
|
||||||
, ("occurrence", SortColumn $ queryExamOccurrence >>> (E.?. ExamOccurrenceName))
|
, ("occurrence", SortColumn $ queryExamOccurrence >>> (E.?. ExamOccurrenceName))
|
||||||
|
, ("result", SortColumn $ queryExamResult >>> (E.?. ExamResultResult))
|
||||||
|
, ("result-bool", SortColumn $ queryExamResult >>> (E.?. ExamResultResult) >>> E.orderByList [Just ExamVoided, Just ExamNoShow, Just $ ExamAttended Grade50])
|
||||||
]
|
]
|
||||||
dbtFilter = Map.fromList
|
dbtFilter = Map.fromList
|
||||||
[ fltrUserNameEmail queryUser
|
[ fltrUserNameEmail queryUser
|
||||||
@ -247,14 +259,30 @@ postEUsersR tid ssh csh examn = do
|
|||||||
, fltrDegree queryStudyDegree
|
, fltrDegree queryStudyDegree
|
||||||
, fltrFeaturesSemester queryStudyFeatures
|
, fltrFeaturesSemester queryStudyFeatures
|
||||||
, ("occurrence", FilterColumn . E.mkContainsFilterWith Just $ queryExamOccurrence >>> (E.?. ExamOccurrenceName))
|
, ("occurrence", FilterColumn . E.mkContainsFilterWith Just $ queryExamOccurrence >>> (E.?. ExamOccurrenceName))
|
||||||
|
, ("result", FilterColumn . E.mkExactFilterWith Just $ queryExamResult >>> (E.?. ExamResultResult))
|
||||||
|
, ( "result-bool"
|
||||||
|
, FilterColumn $ \row criteria -> if
|
||||||
|
| Set.null criteria -> E.true
|
||||||
|
| otherwise -> let passed :: [ExamResultGrade]
|
||||||
|
passed = filter (\res -> preview (_examResult . passingGrade) res == Just (ExamPassed True)) universeF
|
||||||
|
criteria' = Set.map (fmap $ review passingGrade) criteria
|
||||||
|
criteria''
|
||||||
|
| ExamAttended (ExamPassed True) `Set.member` criteria
|
||||||
|
= criteria' `Set.union` Set.fromList passed
|
||||||
|
| otherwise
|
||||||
|
= criteria'
|
||||||
|
in queryExamResult row E.?. ExamResultResult `E.in_` E.valList (Just <$> Set.toList criteria'')
|
||||||
|
)
|
||||||
]
|
]
|
||||||
dbtFilterUI mPrev = mconcat
|
dbtFilterUI mPrev = mconcat $ catMaybes
|
||||||
[ fltrUserNameEmailUI mPrev
|
[ Just $ fltrUserNameEmailUI mPrev
|
||||||
, fltrUserMatriclenrUI mPrev
|
, Just $ fltrUserMatriclenrUI mPrev
|
||||||
, fltrFieldUI mPrev
|
, Just $ fltrFieldUI mPrev
|
||||||
, fltrDegreeUI mPrev
|
, Just $ fltrDegreeUI mPrev
|
||||||
, fltrFeaturesSemesterUI mPrev
|
, Just $ fltrFeaturesSemesterUI mPrev
|
||||||
, prismAForm (singletonFilter "occurrence") mPrev $ aopt textField (fslI MsgExamOccurrence)
|
, Just $ prismAForm (singletonFilter "occurrence") mPrev $ aopt textField (fslI MsgExamOccurrence)
|
||||||
|
, guardOn examShowGrades $ prismAForm (singletonFilter "result" . maybePrism _PathPiece) mPrev $ aopt (examResultField examGradeField) (fslI MsgExamResult)
|
||||||
|
, guardOn (not examShowGrades) $ prismAForm (singletonFilter "result" . maybePrism _PathPiece) mPrev $ aopt (examResultField examPassedField) (fslI MsgExamResult)
|
||||||
]
|
]
|
||||||
dbtStyle = def { dbsFilterLayout = defaultDBSFilterLayout }
|
dbtStyle = def { dbsFilterLayout = defaultDBSFilterLayout }
|
||||||
dbtParams = DBParamsForm
|
dbtParams = DBParamsForm
|
||||||
|
|||||||
@ -1015,7 +1015,7 @@ examResultField innerField = Field
|
|||||||
, is _ExamNoShow res || is _ExamVoided res
|
, is _ExamNoShow res || is _ExamVoided res
|
||||||
-> return . Right $ Just res
|
-> return . Right $ Just res
|
||||||
| otherwise
|
| otherwise
|
||||||
-> fmap (fmap ExamAttended) <$> fieldParse innerField ts fs
|
-> fmap (fmap ExamAttended) <$> fieldParse innerField (filter (not . (`elem` ["attended", "no-show", "voided"])) ts) fs
|
||||||
, fieldView = \theId name attrs val isReq -> do
|
, fieldView = \theId name attrs val isReq -> do
|
||||||
innerId <- newIdent
|
innerId <- newIdent
|
||||||
let
|
let
|
||||||
@ -1025,11 +1025,26 @@ examResultField innerField = Field
|
|||||||
innerVal = val >>= maybe (Left "") return . preview _ExamAttended
|
innerVal = val >>= maybe (Left "") return . preview _ExamAttended
|
||||||
[whamlet|
|
[whamlet|
|
||||||
$newline never
|
$newline never
|
||||||
<select id=#{theId} name=#{name} *{attrs} :isReq:required>
|
<div>
|
||||||
<option value="attended" :is _ExamAttended val':selected>_{MsgExamResultAttended}
|
<select id=#{theId} name=#{name} *{attrs} :isReq:required style="display: inline-block">
|
||||||
<option value="no-show" :is _ExamNoShow val':selected>_{MsgExamResultNoShow}
|
<option value="attended" :is _ExamAttended val':selected>_{MsgExamResultAttended}
|
||||||
<option value="voided" :is _ExamVoided val':selected>_{MsgExamResultVoided}
|
<option value="no-show" :is _ExamNoShow val':selected>_{MsgExamResultNoShow}
|
||||||
<fieldset uw-interactive-fieldset data-conditional-input=#{theId} data-conditional-value="attended">
|
<option value="voided" :is _ExamVoided val':selected>_{MsgExamResultVoided}
|
||||||
^{fieldView innerField innerId name attrs innerVal False}
|
<fieldset uw-interactive-fieldset .interactive-fieldset__target data-conditional-input=#{theId} data-conditional-value="attended" style="display: inline-block">
|
||||||
|
^{fieldView innerField innerId name attrs innerVal False}
|
||||||
|]
|
|]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
examGradeField :: forall m.
|
||||||
|
( MonadHandler m
|
||||||
|
, HandlerSite m ~ UniWorX
|
||||||
|
)
|
||||||
|
=> Field m ExamGrade
|
||||||
|
examGradeField = hoistField liftHandlerT $ selectField optionsFinite
|
||||||
|
|
||||||
|
examPassedField :: forall m.
|
||||||
|
( MonadHandler m
|
||||||
|
, HandlerSite m ~ UniWorX
|
||||||
|
)
|
||||||
|
=> Field m ExamPassed
|
||||||
|
examPassedField = hoistField liftHandlerT $ selectField optionsFinite
|
||||||
|
|||||||
@ -12,7 +12,8 @@ module Model.Types.Exam
|
|||||||
import Import.NoModel
|
import Import.NoModel
|
||||||
import Model.Types.Common
|
import Model.Types.Common
|
||||||
|
|
||||||
import Control.Lens
|
import Control.Lens hiding (universe)
|
||||||
|
import Utils.Lens.TH
|
||||||
|
|
||||||
import qualified Data.Csv as Csv
|
import qualified Data.Csv as Csv
|
||||||
|
|
||||||
@ -28,6 +29,7 @@ deriveJSON defaultOptions
|
|||||||
} ''ExamResult'
|
} ''ExamResult'
|
||||||
derivePersistFieldJSON ''ExamResult'
|
derivePersistFieldJSON ''ExamResult'
|
||||||
|
|
||||||
|
makeLenses_ ''ExamResult'
|
||||||
makePrisms ''ExamResult'
|
makePrisms ''ExamResult'
|
||||||
|
|
||||||
instance PathPiece res => PathPiece (ExamResult' res) where
|
instance PathPiece res => PathPiece (ExamResult' res) where
|
||||||
@ -73,6 +75,14 @@ instance Csv.FromField res => Csv.FromField (ExamResult' res) where
|
|||||||
parseField "no-show" = pure ExamNoShow
|
parseField "no-show" = pure ExamNoShow
|
||||||
parseField x = ExamAttended <$> Csv.parseField x
|
parseField x = ExamAttended <$> Csv.parseField x
|
||||||
|
|
||||||
|
instance Universe res => Universe (ExamResult' res) where
|
||||||
|
universe = concat
|
||||||
|
[ pure ExamVoided
|
||||||
|
, pure ExamNoShow
|
||||||
|
, ExamAttended <$> universe
|
||||||
|
]
|
||||||
|
instance Finite res => Finite (ExamResult' res)
|
||||||
|
|
||||||
|
|
||||||
data ExamBonusRule = ExamNoBonus
|
data ExamBonusRule = ExamNoBonus
|
||||||
| ExamBonusPoints
|
| ExamBonusPoints
|
||||||
|
|||||||
@ -140,6 +140,7 @@ makeLenses_ ''PredDNF
|
|||||||
|
|
||||||
makeLenses_ ''ExamBonusRule
|
makeLenses_ ''ExamBonusRule
|
||||||
makeLenses_ ''ExamGradingRule
|
makeLenses_ ''ExamGradingRule
|
||||||
|
makeLenses_ ''ExamResult
|
||||||
|
|
||||||
makeLenses_ ''UTCTime
|
makeLenses_ ''UTCTime
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user