feat(exams): exam finish button

This commit is contained in:
Gregor Kleen 2021-03-19 00:05:56 +01:00
parent a6390eccbd
commit 78d0f2522d
11 changed files with 146 additions and 18 deletions

View File

@ -588,13 +588,35 @@ section
padding-bottom: 30px
border-bottom: 1px solid #d3d3d3
+ section
& + section, & + .two-column-sections
margin-top: 20px
&:last-child
border-bottom: none
padding-bottom: 0px
.two-column-sections
padding-bottom: 30px
border-bottom: 1px solid #d3d3d3
& + section, & + .two-column-sections
margin-top: 20px
&:last-child
border-bottom: none
padding-bottom: 0px
@media (min-width: 768px)
display: flex
justify-content: space-between
& > section
padding: 0
border: none
margin: 0 auto
width: calc(50% - 7px)
.headline-one
margin-bottom: 10px

View File

@ -2551,8 +2551,13 @@ ExamCloseTip: Wenn eine Prüfung abgeschlossen wird, werden Prüfungsbeauftragte
ExamCloseReminder: Bitte schließen Sie die Prüfung frühstmöglich, sobald die Prüfungsleistungen sich voraussichtlich nicht mehr ändern werden. Z.B. direkt nach der Klausureinsicht.
ExamDidClose: Prüfung erfolgreich abgeschlossen
ExamCloseTipOnFinished: Die Prüfung wird automatisch abgeschlossen, also Prüfungsbeauftragte, die im System Note einsehen, benachrichtigt und danach bei Änderungen informiert, sobald die Noten für die Prüfungsteilnehmer veröffentlicht werden.
ExamFinishHeading: Prüfungsergebnisse sichtbar schalten
BtnFinishExam: Prüfungsergebnisse sichtbar schalten
ExamFinishTip: Wenn die Prufungsergebnisse sichtbar geschaltet sind, können Teilnehmende ihre Ergebnisse im System einsehen und werden über diesen Umstand informiert. Es wird die Prüfungfrist „_{MsgExamFinished}“ auf den aktuellen Zeitpunkt gesetzt.
ExamDidFinish: Prüfungsergbnisse sichtbar geschaltet
ExamClosedSince time@Text: Prüfung abgeschlossen seit #{time}
ExamFinishedSince time@Text: Prüfungsergebnisse sichtbar seit #{time}
LecturerInfoTooltipNew: Neues Feature
LecturerInfoTooltipProblem: Feature mit bekannten Problemen

View File

@ -2551,8 +2551,13 @@ ExamCloseTip: When an exam is closed all relevant exam offices, which pull exam
ExamCloseReminder: Please close the exam as soon as possible, when exam achievements are no longer expected to change e.g. after inspection of the exam has concluced.
ExamDidClose: Successfully closed exam
ExamCloseTipOnFinished: The exam will be closed automatically as soon as exam participants are informed of their exam achievements. That means exam offices will be able notified once and after that each time a grade changes.
ExamFinishHeading: Make results visible
BtnFinishExam: Make results visible
ExamFinishTip: After results are made visible participants are notified and can view their result in Uni2work. The exam timestamp “_{MsgExamFinished}” will be set to the current time.
ExamDidFinish: Successfully made results visible
ExamClosedSince time: Exam closed since #{time}
ExamFinishedSince time: Exam results visible since #{time}
LecturerInfoTooltipNew: New feature
LecturerInfoTooltipProblem: Feature with known issues

View File

@ -7,7 +7,7 @@ import Handler.Exam.Register
import Handler.Exam.AutoOccurrence (examAutoOccurrenceCalculateWidget)
import Handler.ExamOffice.Exam (examCloseWidget)
import Handler.ExamOffice.Exam (examCloseWidget, examFinishWidget)
import Data.Map ((!?))
import qualified Data.Map as Map
@ -106,6 +106,7 @@ getEShowR tid ssh csh examn = do
partNumbersShown = lecturerInfoShown
examClosedShown = lecturerInfoShown && isn't _ExamCloseOnFinished' schoolExamCloseMode
showCloseWidget = lecturerInfoShown
showFinishWidget = lecturerInfoShown && is _Nothing examFinished
showAutoOccurrenceCalculateWidget = lecturerInfoShown
showRegisteredCount = lecturerInfoShown
examFinishedMsg = if lecturerInfoShown then MsgExamFinished else MsgExamFinishedParticipant
@ -191,6 +192,7 @@ getEShowR tid ssh csh examn = do
showOccurrenceMappingColumn = examOccurrenceRuleAutomatic examOccurrenceRule && occurrenceAssignmentsShown && is _Just examExamOccurrenceMapping
closeWgt <- examCloseWidget (SomeRoute $ CExamR tid ssh csh examn EUsersR) eId
finishWgt <- examFinishWidget (SomeRoute $ CExamR tid ssh csh examn EUsersR) eId
let heading = prependCourseTitle tid ssh csh $ CI.original examName

View File

@ -14,7 +14,7 @@ import Handler.Utils.StudyFeatures
import Handler.Exam.AutoOccurrence (examAutoOccurrenceCalculateWidget)
import Handler.ExamOffice.Exam (examCloseWidget)
import Handler.ExamOffice.Exam (examCloseWidget, examFinishWidget)
import qualified Database.Esqueleto as E
import qualified Database.Esqueleto.Utils as E
@ -1131,6 +1131,7 @@ postEUsersR tid ssh csh examn = do
redirect $ CExamR tid ssh csh examn EUsersR
closeWgt <- examCloseWidget (SomeRoute $ CExamR tid ssh csh examn EUsersR) eId
finishWgt <- examFinishWidget (SomeRoute $ CExamR tid ssh csh examn EUsersR) eId
siteLayoutMsg (prependCourseTitle tid ssh csh MsgExamUsersHeading) $ do
setTitleI $ prependCourseTitle tid ssh csh MsgExamUsersHeading

View File

@ -2,7 +2,7 @@
module Handler.ExamOffice.Exam
( getEGradesR, postEGradesR
, examCloseWidget
, examCloseWidget, examFinishWidget
) where
import Import
@ -79,6 +79,47 @@ examCloseWidget dest eId = do
return $(widgetFile "widgets/exam-close")
data ButtonFinishExam = BtnFinishExam
deriving (Enum, Eq, Ord, Bounded, Read, Show, Generic, Typeable)
instance Universe ButtonFinishExam
instance Finite ButtonFinishExam
nullaryPathPiece ''ButtonFinishExam $ camelToPathPiece' 1
embedRenderMessage ''UniWorX ''ButtonFinishExam id
instance Button UniWorX ButtonFinishExam where
btnClasses BtnFinishExam = [BCIsButton]
examFinishWidget :: SomeRoute UniWorX -> ExamId -> Handler Widget
examFinishWidget dest eId = do
Exam{examFinished} <- runDB $ get404 eId
examFinishedStr <- for examFinished $ formatTime SelFormatDateTime
((finishRes, finishView'), finishEnc) <- runFormPost $ identifyForm BtnFinishExam buttonForm
formResult finishRes $ \case
BtnFinishExam -> do
now <- liftIO getCurrentTime
unless (is _Nothing examFinished) $
invalidArgs ["Exam is already finished"]
runDB $ update eId [ ExamFinished =. Just now ]
addMessageI Success MsgExamDidFinish
redirect dest
let finishView = wrapForm finishView' def
{ formSubmit = FormNoSubmit
, formAction = Just dest
, formEncoding = finishEnc
}
return $(widgetFile "widgets/exam-finish")
type ExamUserTableExpr = ( E.SqlExpr (Entity ExamResult)
`E.InnerJoin` E.SqlExpr (Entity User)
)
@ -186,7 +227,7 @@ getEGradesR = postEGradesR
postEGradesR tid ssh csh examn = do
uid <- requireAuthId
now <- liftIO getCurrentTime
((usersResult, examUsersTable), Entity eId _) <- runDB $ do
((usersResult, examUsersTable), Entity eId Exam{examFinished}) <- runDB $ do
exam@(Entity eid Exam{..}) <- fetchExam tid ssh csh examn
Course{..} <- getJust examCourse
@ -431,6 +472,7 @@ postEGradesR tid ssh csh examn = do
whenIsJust usersResult join
closeWgt <- examCloseWidget (SomeRoute $ CExamR tid ssh csh examn EGradesR) eId
finishWgt <- examFinishWidget (SomeRoute $ CExamR tid ssh csh examn EGradesR) eId
hasUsers <- hasReadAccessTo $ CExamR tid ssh csh examn EUsersR
siteLayoutMsg (prependCourseTitle tid ssh csh MsgExamOfficeExamUsersHeading) $ do

View File

@ -957,4 +957,4 @@ correctionInvisibleWidget tid ssh csh shn cID (Entity subId sub) = runMaybeT $ d
unless (NTop (Just now) >= NTop examFinished) $
tellPoint CorrectionInvisibleExamUnfinished
return $ notificationWidget NotificationBroad Warning $(widgetFile "submission-correction-invisible")
return $ notification NotificationBroad =<< messageIconWidget Warning IconInvisible $(widgetFile "submission-correction-invisible")

View File

@ -1,6 +1,13 @@
$newline never
<section>
^{closeWgt}
$if is _Nothing examFinished
<div .two-column-sections>
<section>
^{closeWgt}
<section>
^{finishWgt}
$else
<section>
^{closeWgt}
<section>
$if hasUsers
^{examGradesExplanation}

View File

@ -140,12 +140,31 @@ $maybe desc <- examDescription
$if is _Nothing (examRequiredEquipment examExamMode)
^{notificationPersonalIdentification}
$if showCloseWidget && is _Nothing examClosed
<section>
<h2>
_{MsgExamCloseHeading}
\ ^{isVisible False}
^{closeWgt}
$if (showCloseWidget && is _Nothing examClosed) && (showFinishWidget && is _Nothing examFinished)
<div .two-column-sections>
<section>
<h2>
_{MsgExamCloseHeading}
\ ^{isVisible False}
^{closeWgt}
<section>
<h2>
_{MsgExamFinishHeading}
\ ^{isVisible False}
^{finishWgt}
$else
$if showCloseWidget && is _Nothing examClosed
<section>
<h2>
_{MsgExamCloseHeading}
\ ^{isVisible False}
^{closeWgt}
$if showFinishWidget && is _Nothing examFinished
<section>
<h2>
_{MsgExamFinishHeading}
\ ^{isVisible False}
^{finishWgt}
$if examOccurrenceRuleAutomatic examOccurrenceRule && showAutoOccurrenceCalculateWidget
<section>
<h2>
@ -318,6 +337,8 @@ $if (gradingShown || partsShown) && not (null examParts)
$if partNumbersShown
<td>
<td>
$if showPartSheets
<td>
<td .table__td>
#{showFixed True sumMaxPoints}
<td>
@ -327,6 +348,8 @@ $if (gradingShown || partsShown) && not (null examParts)
<td .table__td>
<a href=@{CourseR tid ssh csh SheetListR}>
_{MsgExamBonusAchieved}
$if showPartSheets
<td>
$if showMaxPoints
<td .table__td>
$if showAchievedPoints
@ -336,6 +359,8 @@ $if (gradingShown || partsShown) && not (null examParts)
$if partNumbersShown
<td>
<td>
$if showPartSheets
<td>
$if showMaxPoints
<td>
$if showAchievedPoints
@ -349,6 +374,8 @@ $if (gradingShown || partsShown) && not (null examParts)
$if partNumbersShown
<td>
<td>
$if showPartSheets
<td>
$if showMaxPoints
<td .table__td>
#{showFixed True sumMaxPoints}

View File

@ -1,8 +1,17 @@
$newline never
<section>
$if is _Nothing examClosed
<h2>_{MsgExamCloseHeading}
^{closeWgt}
$if is _Nothing examFinished
<div .two-column-sections>
<section>
<h2>_{MsgExamCloseHeading}
^{closeWgt}
<section>
<h2>_{MsgExamFinishHeading}
^{finishWgt}
$else
<section>
$if is _Nothing examClosed
<h2>_{MsgExamCloseHeading}
^{closeWgt}
$if examOccurrenceRuleAutomatic examOccurrenceRule
<section>
<h2>_{MsgExamAutoOccurrenceHeading}

View File

@ -0,0 +1,8 @@
$newline never
$maybe finished <- examFinishedStr
<p>
_{MsgExamFinishedSince finished}
$nothing
<p .explanation>
_{MsgExamFinishTip}
^{finishView}