Skip to content

Commit 14aa91b

Browse files
committed
feat: validate pre-planned exahm exams
1 parent 5a1f6ce commit 14aa91b

File tree

2 files changed

+161
-8
lines changed

2 files changed

+161
-8
lines changed

cmd/validate.go

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -15,14 +15,15 @@ var (
1515
Use: "validate",
1616
Short: "validate [subcommand] [-s <seconds>]",
1717
Long: `Validate the plan.
18-
all --- guess what :-)
19-
conflicts --- check conflicts for each student
20-
constraints --- check if constraints hold
21-
db --- data base entries
22-
rooms --- check room constraints
23-
zpa --- check if the plan on ZPA is the same here
24-
invigilator-reqs. --- check if invigilator requirements are met
25-
invigilator-slots --- check if invigilator slots are okay
18+
all --- guess what :-)
19+
conflicts --- check conflicts for each student
20+
constraints --- check if constraints hold
21+
preplanned-exahm-rooms --- validate exahm pre-planned rooms
22+
db --- data base entries
23+
rooms --- check room constraints
24+
zpa --- check if the plan on ZPA is the same here
25+
invigilator-reqs. --- check if invigilator requirements are met
26+
invigilator-slots --- check if invigilator slots are okay
2627
`,
2728
Args: cobra.MinimumNArgs(1),
2829
Run: func(cmd *cobra.Command, args []string) {
@@ -53,6 +54,9 @@ var (
5354
case "db":
5455
validations = append(validations, plexams.ValidateDB)
5556

57+
case "preplanned-exahm-rooms":
58+
validations = append(validations, plexams.ValidatePrePlannedExahmRooms)
59+
5660
case "rooms":
5761
validations = append(validations,
5862
[]func() error{

plexams/validate_exahm_rooms.go

Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
package plexams
2+
3+
import (
4+
"context"
5+
"fmt"
6+
"time"
7+
8+
"github.com/logrusorgru/aurora"
9+
"github.com/obcode/plexams.go/graph/model"
10+
"github.com/rs/zerolog/log"
11+
"github.com/theckman/yacspin"
12+
)
13+
14+
func (p *Plexams) ValidatePrePlannedExahmRooms() error {
15+
ctx := context.Background()
16+
cfg := yacspin.Config{
17+
Frequency: 100 * time.Millisecond,
18+
CharSet: yacspin.CharSets[69],
19+
Suffix: aurora.Sprintf(aurora.Cyan(" validating pre-planned exahm rooms (booked and enough seats)")),
20+
SuffixAutoColon: true,
21+
StopCharacter: "✓",
22+
StopColors: []string{"fgGreen"},
23+
StopFailMessage: "error",
24+
StopFailCharacter: "✗",
25+
StopFailColors: []string{"fgRed"},
26+
}
27+
28+
spinner, err := yacspin.New(cfg)
29+
if err != nil {
30+
log.Debug().Err(err).Msg("cannot create spinner")
31+
}
32+
err = spinner.Start()
33+
if err != nil {
34+
log.Debug().Err(err).Msg("cannot start spinner")
35+
}
36+
37+
validationMessages := make([]string, 0)
38+
39+
exams := make([]*model.GeneratedExam, 0)
40+
generatedExams, err := p.dbClient.GetGeneratedExams(ctx)
41+
if err != nil {
42+
log.Error().Err(err).
43+
Msg("cannot get generated exams")
44+
return err
45+
}
46+
47+
for _, exam := range generatedExams {
48+
if exam.Constraints != nil && exam.Constraints.RoomConstraints != nil &&
49+
(exam.Constraints.RoomConstraints.Exahm || exam.Constraints.RoomConstraints.Seb) {
50+
exams = append(exams, exam)
51+
}
52+
}
53+
54+
rooms, err := p.Rooms(ctx)
55+
if err != nil {
56+
log.Error().Err(err).
57+
Msg("cannot get rooms")
58+
}
59+
roomsMap := make(map[string]*model.Room)
60+
for _, room := range rooms {
61+
roomsMap[room.Name] = room
62+
}
63+
64+
for _, exam := range exams {
65+
prePlannedRooms, err := p.dbClient.PrePlannedRoomsForExam(ctx, exam.Ancode)
66+
if err != nil {
67+
log.Error().Err(err).
68+
Int("ancode", exam.Ancode).
69+
Msg("error while trying to get prePlannedRooms")
70+
}
71+
for _, prePlannedRoom := range prePlannedRooms {
72+
room := roomsMap[prePlannedRoom.RoomName]
73+
if exam.Constraints.RoomConstraints.Seb && !room.Seb {
74+
validationMessages = append(validationMessages, aurora.Sprintf(aurora.Red("Room %s for %d. %s (%s) is not SEB-Room"),
75+
aurora.Magenta(room.Name), aurora.Cyan(exam.Ancode), aurora.Cyan(exam.ZpaExam.Module), aurora.Cyan(exam.ZpaExam.MainExamer)))
76+
}
77+
78+
if exam.Constraints.RoomConstraints.Exahm && !room.Exahm {
79+
validationMessages = append(validationMessages, aurora.Sprintf(aurora.Red("Room %s for %d. %s (%s) is not EXaHM-Room"),
80+
aurora.Magenta(room.Name), aurora.Cyan(exam.Ancode), aurora.Cyan(exam.ZpaExam.Module), aurora.Cyan(exam.ZpaExam.MainExamer)))
81+
}
82+
}
83+
84+
// check if exam is planned in this slot if room is allowed
85+
planEntry, err := p.dbClient.PlanEntry(ctx, exam.Ancode)
86+
if err != nil {
87+
log.Error().Err(err).
88+
Int("ancode", exam.Ancode).
89+
Msg("cannot get plan entry for exam")
90+
}
91+
if planEntry == nil {
92+
validationMessages = append(validationMessages, aurora.Sprintf(aurora.Red("Exam %d. %s (%s) has no plan entry yet"),
93+
aurora.Cyan(exam.Ancode), aurora.Cyan(exam.ZpaExam.Module), aurora.Cyan(exam.ZpaExam.MainExamer)))
94+
} else {
95+
roomsForSlot, err := p.RoomsForSlot(ctx, planEntry.DayNumber, planEntry.SlotNumber)
96+
if err != nil {
97+
log.Error().Err(err).
98+
Int("day", planEntry.DayNumber).
99+
Int("slot", planEntry.SlotNumber).
100+
Msg("cannot rooms for slot")
101+
}
102+
for _, prePlannedRoom := range prePlannedRooms {
103+
found := false
104+
for _, roomInSlot := range roomsForSlot.RoomNames {
105+
if prePlannedRoom.RoomName == roomInSlot {
106+
found = true
107+
break
108+
}
109+
}
110+
if !found {
111+
validationMessages = append(validationMessages, aurora.Sprintf(aurora.Red("Room %s for Exam %d. %s (%s) in slot (%d/%d) is not allowed"),
112+
aurora.Magenta(prePlannedRoom.RoomName), aurora.Cyan(exam.Ancode), aurora.Cyan(exam.ZpaExam.Module), aurora.Cyan(exam.ZpaExam.MainExamer),
113+
aurora.Blue(planEntry.DayNumber), aurora.Blue(planEntry.SlotNumber)))
114+
}
115+
}
116+
}
117+
118+
// check if rooms have enough seats
119+
seats := 0
120+
for _, prePlannedRoom := range prePlannedRooms {
121+
room := roomsMap[prePlannedRoom.RoomName]
122+
seats += room.Seats
123+
}
124+
if seats < exam.StudentRegsCount {
125+
validationMessages = append(validationMessages, aurora.Sprintf(aurora.Red("Not enough seats for Exam %d. %s (%s): %d seats planned, but %d students"),
126+
aurora.Cyan(exam.Ancode), aurora.Cyan(exam.ZpaExam.Module), aurora.Cyan(exam.ZpaExam.MainExamer),
127+
aurora.Cyan(seats), aurora.Cyan(exam.StudentRegsCount)))
128+
}
129+
}
130+
131+
if len(validationMessages) > 0 {
132+
spinner.StopFailMessage(aurora.Sprintf(aurora.Red("%d problems found"), len(validationMessages)))
133+
err = spinner.StopFail()
134+
if err != nil {
135+
log.Debug().Err(err).Msg("cannot stop spinner")
136+
}
137+
for _, msg := range validationMessages {
138+
fmt.Printf(" ↪ %s\n", msg)
139+
}
140+
141+
} else {
142+
err = spinner.Stop()
143+
if err != nil {
144+
log.Debug().Err(err).Msg("cannot stop spinner")
145+
}
146+
}
147+
148+
return nil
149+
}

0 commit comments

Comments
 (0)