feat(exam-correct): accept grades besides exam part results

This commit is contained in:
Sarah Vaupel 2020-02-05 16:02:48 +01:00
parent cdfca514fc
commit be187ae907

View File

@ -29,7 +29,8 @@ deriveJSON defaultOptions
data CorrectInterfaceResponse data CorrectInterfaceResponse
= CorrectInterfaceResponseSuccess = CorrectInterfaceResponseSuccess
{ cirsUser :: CorrectInterfaceUser { cirsUser :: CorrectInterfaceUser
, cirsResults :: Map ExamPartNumber (Maybe Points) , cirsResults :: Map ExamPartNumber (Maybe ExamResultPoints)
, cirsGrade :: Maybe ExamResultPassedGrade
, cirsTime :: UTCTime , cirsTime :: UTCTime
} }
| CorrectInterfaceResponseAmbiguous | CorrectInterfaceResponseAmbiguous
@ -52,6 +53,7 @@ data CorrectInterfaceRequest
= CorrectInterfaceRequest = CorrectInterfaceRequest
{ ciqUser :: Either Text (CryptoID UUID (Key User)) { ciqUser :: Either Text (CryptoID UUID (Key User))
, ciqResults :: Maybe (NonNull (Map ExamPartNumber (Maybe Points))) , ciqResults :: Maybe (NonNull (Map ExamPartNumber (Maybe Points)))
, ciqGrade :: Maybe ExamResultPassedGrade
} }
instance FromJSON CorrectInterfaceRequest where instance FromJSON CorrectInterfaceRequest where
@ -59,6 +61,7 @@ instance FromJSON CorrectInterfaceRequest where
ciqUser <- Right <$> o JSON..: "user" <|> Left <$> o JSON..: "user" ciqUser <- Right <$> o JSON..: "user" <|> Left <$> o JSON..: "user"
results <- o JSON..:? "results" results <- o JSON..:? "results"
ciqResults <- for results $ maybe (fail "Results may not be nullable") return . fromNullable ciqResults <- for results $ maybe (fail "Results may not be nullable") return . fromNullable
ciqGrade <- o JSON..:? "grade"
return CorrectInterfaceRequest{..} return CorrectInterfaceRequest{..}
@ -92,10 +95,10 @@ postECorrectR :: TermId -> SchoolId -> CourseShorthand -> ExamName -> Handler Vo
postECorrectR tid ssh csh examn = do postECorrectR tid ssh csh examn = do
MsgRenderer mr <- getMsgRenderer MsgRenderer mr <- getMsgRenderer
CorrectInterfaceRequest{ciqUser,ciqResults} <- requireCheckJsonBody CorrectInterfaceRequest{..} <- requireCheckJsonBody
response <- runDB $ do response <- runDB $ do
Entity eId _ <- fetchExam tid ssh csh examn Entity eId Exam{..} <- fetchExam tid ssh csh examn
euid <- traverse decrypt ciqUser euid <- traverse decrypt ciqUser
participantMatches <- E.select . E.from $ \(examRegistration `E.InnerJoin` user) -> do participantMatches <- E.select . E.from $ \(examRegistration `E.InnerJoin` user) -> do
@ -130,16 +133,17 @@ postECorrectR tid ssh csh examn = do
if if
-- on no-op request, answer with 200 and a set of all participant matches -- on no-op request, answer with 200 and a set of all participant matches
| is _Nothing ciqResults -> do | is _Nothing ciqResults, is _Nothing ciqGrade -> do
users <- traverse userToResponse participantMatches users <- traverse userToResponse participantMatches
return CorrectInterfaceResponseNoOp return CorrectInterfaceResponseNoOp
{ cirnUsers = Set.fromList users { cirnUsers = Set.fromList users
} }
-- on match with exactly one exam participant, insert results and answer with 200 -- on match with exactly one exam participant, insert results and/or grade and answer with 200
| [match@(Entity uid _)] <- participantMatches, Just results <- ciqResults -> do | [match@(Entity uid _)] <- participantMatches -> do
now <- liftIO getCurrentTime now <- liftIO getCurrentTime
newExamPartResults <- iforM (toNullable results) $ \partNumber mPartResult -> do newExamPartResults <- if
| Just results <- ciqResults -> iforM (toNullable results) $ \partNumber mPartResult -> do
examPartId <- getKeyBy404 $ UniqueExamPartNumber eId partNumber examPartId <- getKeyBy404 $ UniqueExamPartNumber eId partNumber
mOldResult <- getBy $ UniqueExamPartResult examPartId uid mOldResult <- getBy $ UniqueExamPartResult examPartId uid
if if
@ -150,7 +154,7 @@ postECorrectR tid ssh csh examn = do
| Just partResult <- mPartResult -> let | Just partResult <- mPartResult -> let
mOld = (examPartResultResult . entityVal) <$> mOldResult mOld = (examPartResultResult . entityVal) <$> mOldResult
mNew = ExamAttended <$> mPartResult mNew = ExamAttended <$> mPartResult
resultVal = _entityVal . _examPartResultResult . _ExamAttended resultVal = _entityVal . _examPartResultResult
in if in if
| mOld /= mNew -> do | mOld /= mNew -> do
newExamPartResult <- upsert ExamPartResult newExamPartResult <- upsert ExamPartResult
@ -165,11 +169,42 @@ postECorrectR tid ssh csh examn = do
audit $ TransactionExamPartResultEdit examPartId uid audit $ TransactionExamPartResultEdit examPartId uid
return $ newExamPartResult ^? resultVal return $ newExamPartResult ^? resultVal
| otherwise -> return $ mOldResult ^? _Just . resultVal | otherwise -> return $ mOldResult ^? _Just . resultVal
| otherwise -> return Nothing | otherwise -> return Nothing
| otherwise -> return mempty
newExamResult <- do
mOldResult <- getBy $ UniqueExamResult eId uid
if
| Just (Entity oldId _) <- mOldResult, is _Nothing ciqGrade -> do
delete oldId
audit $ TransactionExamResultDeleted eId uid
return Nothing
| Just result <- ciqGrade -> let
mOld = view passedGrade . examResultResult . entityVal <$> mOldResult
resultGrade = review passedGrade result
passedGrade :: Iso' ExamResultGrade ExamResultPassedGrade
passedGrade = iso (fmap $ bool (Left . view passingGrade) Right examShowGrades) (fmap $ either (review passingGrade) id)
in if
| ciqGrade /= mOld -> do
newResult <- upsert ExamResult
{ examResultExam = eId
, examResultUser = uid
, examResultResult = resultGrade
, examResultLastChanged = now
}
[ ExamResultResult =. resultGrade
, ExamResultLastChanged =. now
]
audit $ TransactionExamResultEdit eId uid
return $ newResult ^? _entityVal . _examResultResult . passedGrade
| otherwise -> return $ mOldResult ^? _Just . _entityVal . _examResultResult . passedGrade
| otherwise -> return Nothing
user <- userToResponse match user <- userToResponse match
return CorrectInterfaceResponseSuccess return CorrectInterfaceResponseSuccess
{ cirsUser = user { cirsUser = user
, cirsResults = newExamPartResults , cirsResults = newExamPartResults
, cirsGrade = newExamResult
, cirsTime = now , cirsTime = now
} }