fix: improve exam occurrence ui

This commit is contained in:
Gregor Kleen 2020-01-11 23:44:47 +01:00
parent 14bb020fe9
commit 83fa9c9c69
11 changed files with 33 additions and 22 deletions

View File

@ -1541,8 +1541,8 @@ ExamBonusRound: Bonus runden auf
ExamBonusRoundNonPositive: Vielfaches, auf das gerundet werden soll, muss positiv und größer null sein ExamBonusRoundNonPositive: Vielfaches, auf das gerundet werden soll, muss positiv und größer null sein
ExamBonusRoundTip: Bonuspunkte werden kaufmännisch auf ein Vielfaches der angegeben Zahl gerundet. ExamBonusRoundTip: Bonuspunkte werden kaufmännisch auf ein Vielfaches der angegeben Zahl gerundet.
ExamAutomaticOccurrenceAssignment: Automatische oder selbständige Termin- bzw. Raumzuteilung ExamAutomaticOccurrenceAssignment: Termin- bzw. Raumzuteilung
ExamAutomaticOccurrenceAssignmentTip: Sollen Prüfungsteilnehmer automatisch auf die zur Verfügung stehenden Räume bzw. Termine verteilt werden oder sich selbstständig einen Raum bzw. Termin aussuchen dürfen? Manuelle Umverteilung bzw. vorheriges Festlegen von Zuteilungen einzelner Teilnehmer ist trotzdem möglich. ExamAutomaticOccurrenceAssignmentTip: Sollen Prüfungsteilnehmer automatisch auf die zur Verfügung stehenden Räume bzw. Termine verteilt werden, sich selbstständig einen Raum bzw. Termin aussuchen dürfen oder manuell durch Kursverwalter zugeteilt werden? Manuelle Umverteilung bzw. vorheriges Festlegen von Zuteilungen einzelner Teilnehmer ist trotzdem möglich.
ExamOccurrenceRule: Verfahren ExamOccurrenceRule: Verfahren
ExamOccurrenceRuleParticipant: Termin- bzw. Raumzuteilungsverfahren ExamOccurrenceRuleParticipant: Termin- bzw. Raumzuteilungsverfahren
ExamRoomManual': Keine automatische bzw. selbstständige Zuteilung ExamRoomManual': Keine automatische bzw. selbstständige Zuteilung

View File

@ -1540,7 +1540,7 @@ ExamBonusRoundNonPositive: Rounding multiple must be positive and greater than z
ExamBonusRoundTip: Bonus points are rounded commercially to a multiple of the given number ExamBonusRoundTip: Bonus points are rounded commercially to a multiple of the given number
ExamAutomaticOccurrenceAssignment: Selection of occurrences/rooms for/by participants ExamAutomaticOccurrenceAssignment: Selection of occurrences/rooms for/by participants
ExamAutomaticOccurrenceAssignmentTip: Should exam participants be distributed automatically among the configured occurrences/rooms? Should they instead be permitted to autonomously choose an occurrence/a room? Manipulation of the distribution and manually assigning participants remains possible. ExamAutomaticOccurrenceAssignmentTip: Should exam participants be distributed automatically among the configured occurrences/rooms, should they instead be permitted to autonomously choose an occurrence/a room, or should they be assigned to occurrences/rooms manually by course administrators? Manipulation of the distribution and manually assigning participants remains possible.
ExamOccurrenceRule: Procedure ExamOccurrenceRule: Procedure
ExamOccurrenceRuleParticipant: Occurrence/room assignment procedure ExamOccurrenceRuleParticipant: Occurrence/room assignment procedure
ExamRoomManual': No automatic or autonomous assignment ExamRoomManual': No automatic or autonomous assignment

View File

@ -3,7 +3,7 @@ Exam
name ExamName name ExamName
gradingRule ExamGradingRule Maybe gradingRule ExamGradingRule Maybe
bonusRule ExamBonusRule Maybe bonusRule ExamBonusRule Maybe
occurrenceRule ExamOccurrenceRule Maybe occurrenceRule ExamOccurrenceRule
visibleFrom UTCTime Maybe visibleFrom UTCTime Maybe
registerFrom UTCTime Maybe registerFrom UTCTime Maybe
registerTo UTCTime Maybe registerTo UTCTime Maybe

View File

@ -778,7 +778,7 @@ tagAccessPredicate AuthExamOccurrenceRegistration = APDB $ \_ route _ -> case ro
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
E.&&. exam E.^. ExamName E.==. E.val examn E.&&. exam E.^. ExamName E.==. E.val examn
E.&&. exam E.^. ExamOccurrenceRule E.==. E.val (Just ExamRoomFifo) E.&&. exam E.^. ExamOccurrenceRule E.==. E.val ExamRoomFifo
guardMExceptT isOccurrenceRegistration (unauthorizedI MsgUnauthorizedExamOccurrenceRegistration) guardMExceptT isOccurrenceRegistration (unauthorizedI MsgUnauthorizedExamOccurrenceRegistration)
return Authorized return Authorized
r -> $unsupportedAuthPredicate AuthExamOccurrenceRegistration r r -> $unsupportedAuthPredicate AuthExamOccurrenceRegistration r

View File

@ -39,7 +39,7 @@ data ExamForm = ExamForm
, efPublicStatistics :: Bool , efPublicStatistics :: Bool
, efGradingRule :: Maybe ExamGradingRule , efGradingRule :: Maybe ExamGradingRule
, efBonusRule :: Maybe ExamBonusRule , efBonusRule :: Maybe ExamBonusRule
, efOccurrenceRule :: Maybe ExamOccurrenceRule , efOccurrenceRule :: ExamOccurrenceRule
, efCorrectors :: Set (Either UserEmail UserId) , efCorrectors :: Set (Either UserEmail UserId)
, efExamParts :: Set ExamPartForm , efExamParts :: Set ExamPartForm
} }
@ -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)
<*> optionalActionA (examOccurrenceRuleForm $ efOccurrenceRule =<< template) (fslI MsgExamAutomaticOccurrenceAssignment & setTooltip MsgExamAutomaticOccurrenceAssignmentTip) (is _Just . efOccurrenceRule <$> template) <*> (examOccurrenceRuleForm $ efOccurrenceRule <$> template)
<* aformSection MsgExamFormCorrection <* aformSection MsgExamFormCorrection
<*> examCorrectorsForm (efCorrectors <$> template) <*> examCorrectorsForm (efCorrectors <$> template)
<* aformSection MsgExamFormParts <* aformSection MsgExamFormParts

View File

@ -30,7 +30,7 @@ getEShowR tid ssh csh examn = do
let gradingVisible = NTop (Just cTime) >= NTop examFinished let gradingVisible = NTop (Just cTime) >= NTop examFinished
gradingShown <- or2M (return gradingVisible) . hasReadAccessTo $ CExamR tid ssh csh examn EEditR gradingShown <- or2M (return gradingVisible) . hasReadAccessTo $ CExamR tid ssh csh examn EEditR
let occurrenceAssignmentsVisible = NTop (Just cTime) >= NTop examPublishOccurrenceAssignments || examOccurrenceRule == Just ExamRoomFifo let occurrenceAssignmentsVisible = NTop (Just cTime) >= NTop examPublishOccurrenceAssignments || examOccurrenceRule == ExamRoomFifo
occurrenceAssignmentsShown <- or2M (return occurrenceAssignmentsVisible) . hasReadAccessTo $ CExamR tid ssh csh examn EEditR occurrenceAssignmentsShown <- or2M (return occurrenceAssignmentsVisible) . hasReadAccessTo $ CExamR tid ssh csh examn EEditR
examParts <- sortOn (view $ _entityVal . _examPartNumber) <$> selectList [ ExamPartExam ==. eId ] [ Asc ExamPartName ] examParts <- sortOn (view $ _entityVal . _examPartNumber) <$> selectList [ ExamPartExam ==. eId ] [ Asc ExamPartName ]
@ -60,7 +60,7 @@ getEShowR tid ssh csh examn = do
registered <- for mUid $ getBy . UniqueExamRegistration eId registered <- for mUid $ getBy . UniqueExamRegistration eId
mayRegister <- if mayRegister <- if
| examOccurrenceRule == Just ExamRoomFifo -> anyM occurrencesRaw $ \(Entity _ ExamOccurrence{..}, _) -> | examOccurrenceRule == ExamRoomFifo -> anyM occurrencesRaw $ \(Entity _ ExamOccurrence{..}, _) ->
hasWriteAccessTo . CExamR tid ssh csh examName $ ERegisterOccR examOccurrenceName hasWriteAccessTo . CExamR tid ssh csh examName $ ERegisterOccR examOccurrenceName
| otherwise -> hasWriteAccessTo $ CExamR tid ssh csh examName ERegisterR | otherwise -> hasWriteAccessTo $ CExamR tid ssh csh examName ERegisterR
@ -99,7 +99,7 @@ getEShowR tid ssh csh examn = do
let examTimes = all (\(Entity _ ExamOccurrence{..}, _) -> Just examOccurrenceStart == examStart && examOccurrenceEnd == examEnd) occurrences let examTimes = all (\(Entity _ ExamOccurrence{..}, _) -> Just examOccurrenceStart == examStart && examOccurrenceEnd == examEnd) occurrences
registerWidget mOcc registerWidget mOcc
| isRegistered <- is _Just $ join registered | isRegistered <- is _Just $ join registered
, examOccurrenceRule /= Just ExamRoomFifo || (isRegistered && not (any snd occurrences)) , examOccurrenceRule /= ExamRoomFifo || (isRegistered && not (any snd occurrences))
, mayRegister' (entityKey <$> mOcc) = Just $ do , mayRegister' (entityKey <$> mOcc) = Just $ do
(examRegisterForm, examRegisterEnctype) <- liftHandler . generateFormPost . buttonForm' $ bool [BtnExamRegister] [BtnExamDeregister] isRegistered (examRegisterForm, examRegisterEnctype) <- liftHandler . generateFormPost . buttonForm' $ bool [BtnExamRegister] [BtnExamDeregister] isRegistered
[whamlet| [whamlet|
@ -114,7 +114,7 @@ getEShowR tid ssh csh examn = do
, formEncoding = examRegisterEnctype , formEncoding = examRegisterEnctype
, formSubmit = FormNoSubmit , formSubmit = FormNoSubmit
} }
| examOccurrenceRule == Just ExamRoomFifo | examOccurrenceRule == ExamRoomFifo
, Just (Entity occId ExamOccurrence{..}) <- mOcc , Just (Entity occId ExamOccurrence{..}) <- mOcc
, isRegistered <- (== Just occId) $ examRegistrationOccurrence . entityVal =<< join registered , isRegistered <- (== Just occId) $ examRegistrationOccurrence . entityVal =<< join registered
, mayRegister' (Just occId) = Just $ do , mayRegister' (Just occId) = Just $ do
@ -143,7 +143,7 @@ getEShowR tid ssh csh examn = do
showMaxPoints = any (has $ _entityVal . _examPartMaxPoints . _Just) examParts showMaxPoints = any (has $ _entityVal . _examPartMaxPoints . _Just) examParts
showAchievedPoints = not $ null results showAchievedPoints = not $ null results
showOccurrenceRegisterColumn = occurrenceAssignmentsShown || (mayRegister && examOccurrenceRule == Just ExamRoomFifo) showOccurrenceRegisterColumn = occurrenceAssignmentsShown || (mayRegister && examOccurrenceRule == ExamRoomFifo)
markUnregisteredOccurrences mOcc = occurrenceAssignmentsShown && hasRegistration && isn't _Just (registerWidget mOcc) markUnregisteredOccurrences mOcc = occurrenceAssignmentsShown && hasRegistration && isn't _Just (registerWidget mOcc)
let heading = prependCourseTitle tid ssh csh $ CI.original examName let heading = prependCourseTitle tid ssh csh $ CI.original examName

View File

@ -554,10 +554,11 @@ examBonusRuleForm prev = multiActionA actions (fslI MsgExamBonusRule) $ classify
) )
] ]
data ExamOccurrenceRule' = ExamRoomSurname' data ExamOccurrenceRule' = ExamRoomManual'
| ExamRoomFifo'
| ExamRoomSurname'
| ExamRoomMatriculation' | ExamRoomMatriculation'
| ExamRoomRandom' | ExamRoomRandom'
| ExamRoomFifo'
deriving (Eq, Ord, Read, Show, Enum, Bounded, Generic, Typeable) deriving (Eq, Ord, Read, Show, Enum, Bounded, Generic, Typeable)
instance Universe ExamOccurrenceRule' instance Universe ExamOccurrenceRule'
instance Finite ExamOccurrenceRule' instance Finite ExamOccurrenceRule'
@ -567,19 +568,21 @@ embedRenderMessage ''UniWorX ''ExamOccurrenceRule' id
classifyExamOccurrenceRule :: ExamOccurrenceRule -> ExamOccurrenceRule' classifyExamOccurrenceRule :: ExamOccurrenceRule -> ExamOccurrenceRule'
classifyExamOccurrenceRule = \case classifyExamOccurrenceRule = \case
ExamRoomManual -> ExamRoomManual'
ExamRoomSurname -> ExamRoomSurname' ExamRoomSurname -> ExamRoomSurname'
ExamRoomMatriculation -> ExamRoomMatriculation' ExamRoomMatriculation -> ExamRoomMatriculation'
ExamRoomRandom -> ExamRoomRandom' ExamRoomRandom -> ExamRoomRandom'
ExamRoomFifo -> ExamRoomFifo' ExamRoomFifo -> ExamRoomFifo'
examOccurrenceRuleForm :: Maybe ExamOccurrenceRule -> AForm Handler ExamOccurrenceRule examOccurrenceRuleForm :: Maybe ExamOccurrenceRule -> AForm Handler ExamOccurrenceRule
examOccurrenceRuleForm = fmap reverseClassify . areq (selectField optionsFinite) (fslI MsgExamOccurrenceRule) . fmap classifyExamOccurrenceRule examOccurrenceRuleForm = fmap reverseClassify . areq (selectField optionsFinite) (fslI MsgExamAutomaticOccurrenceAssignment & setTooltip MsgExamAutomaticOccurrenceAssignmentTip) . fmap classifyExamOccurrenceRule
where where
reverseClassify = \case reverseClassify = \case
ExamRoomManual' -> ExamRoomManual
ExamRoomFifo' -> ExamRoomFifo
ExamRoomSurname' -> ExamRoomSurname ExamRoomSurname' -> ExamRoomSurname
ExamRoomMatriculation' -> ExamRoomMatriculation ExamRoomMatriculation' -> ExamRoomMatriculation
ExamRoomRandom' -> ExamRoomRandom ExamRoomRandom' -> ExamRoomRandom
ExamRoomFifo' -> ExamRoomFifo
data ExamGradingRule' = ExamGradingKey' data ExamGradingRule' = ExamGradingKey'
deriving (Eq, Ord, Read, Show, Enum, Bounded, Generic, Typeable) deriving (Eq, Ord, Read, Show, Enum, Bounded, Generic, Typeable)

View File

@ -599,6 +599,13 @@ customMigrations = Map.fromListWith (>>)
ALTER TABLE "study_features" DROP COLUMN "sub_field"; ALTER TABLE "study_features" DROP COLUMN "sub_field";
|] |]
) )
, ( AppliedMigrationKey [migrationVersion|29.0.0|] [version|30.0.0|]
, whenM (tableExists "exam") $
[executeQQ|
UPDATE "exam" SET "occurrence_rule" = #{ExamRoomManual} WHERE "occurrence_rule" IS NULL;
ALTER TABLE "exam" ALTER COLUMN "occurrence_rule" SET NOT NULL;
|]
)
] ]

View File

@ -136,10 +136,11 @@ deriveJSON defaultOptions
} ''ExamBonusRule } ''ExamBonusRule
derivePersistFieldJSON ''ExamBonusRule derivePersistFieldJSON ''ExamBonusRule
data ExamOccurrenceRule = ExamRoomSurname data ExamOccurrenceRule = ExamRoomManual
| ExamRoomFifo
| ExamRoomSurname
| ExamRoomMatriculation | ExamRoomMatriculation
| ExamRoomRandom | ExamRoomRandom
| ExamRoomFifo
deriving (Show, Read, Eq, Ord, Generic, Typeable) deriving (Show, Read, Eq, Ord, Generic, Typeable)
deriveJSON defaultOptions deriveJSON defaultOptions
{ fieldLabelModifier = camelToPathPiece' 1 { fieldLabelModifier = camelToPathPiece' 1

View File

@ -76,14 +76,14 @@ $maybe desc <- examDescription
\ ^{isVisible False} \ ^{isVisible False}
<dd .deflist__dd> <dd .deflist__dd>
^{examBonusW bonusRule} ^{examBonusW bonusRule}
$maybe occurrenceRule <- examOccurrenceRule $if examOccurrenceRule /= ExamRoomManual
$if occurrenceAssignmentsShown $if occurrenceAssignmentsShown
<dt .deflist__dt> <dt .deflist__dt>
_{MsgExamOccurrenceRuleParticipant} _{MsgExamOccurrenceRuleParticipant}
$if not occurrenceAssignmentsVisible $if not occurrenceAssignmentsVisible
\ ^{isVisible False} \ ^{isVisible False}
<dd .deflist__dd> <dd .deflist__dd>
_{classifyExamOccurrenceRule occurrenceRule} _{classifyExamOccurrenceRule examOccurrenceRule}
$maybe registerWdgt <- registerWidget Nothing $maybe registerWdgt <- registerWidget Nothing
<dt .deflist__dt>_{MsgExamRegistration} <dt .deflist__dt>_{MsgExamRegistration}
<dd .deflist__dd>^{registerWdgt} <dd .deflist__dd>^{registerWdgt}
@ -108,7 +108,7 @@ $if not (null occurrences)
<th .table__th>_{MsgExamRoomTime} <th .table__th>_{MsgExamRoomTime}
$if showOccurrenceRegisterColumn $if showOccurrenceRegisterColumn
<th .table__th> <th .table__th>
$if examOccurrenceRule == Just ExamRoomFifo $if examOccurrenceRule == ExamRoomFifo
_{MsgExamRoomRegistered} _{MsgExamRoomRegistered}
$else $else
_{MsgExamRoomAssigned} _{MsgExamRoomAssigned}

View File

@ -504,7 +504,7 @@ fillDb = do
, examName = "Klausur" , examName = "Klausur"
, examGradingRule = Nothing , examGradingRule = Nothing
, examBonusRule = Nothing , examBonusRule = Nothing
, examOccurrenceRule = Nothing , examOccurrenceRule = ExamRoomManual
, examVisibleFrom = Just now , examVisibleFrom = Just now
, examRegisterFrom = Just now , examRegisterFrom = Just now
, examRegisterTo = Just $ addUTCTime (14 * nominalDay) now , examRegisterTo = Just $ addUTCTime (14 * nominalDay) now