Skip to content

Commit 810c1a8

Browse files
committed
Merge branch 'dev' into CSCEXAM-224
2 parents 6986b2d + 6159be2 commit 810c1a8

37 files changed

+266
-220
lines changed

app/controllers/user/SessionController.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,9 @@ public class SessionController extends BaseController {
7676
"x-exam-wrong-room",
7777
"wrongRoomData",
7878
"x-exam-wrong-agent-config",
79-
"wrongAgent"
79+
"wrongAgent",
80+
"x-exam-aquarium-login",
81+
"aquariumLogin"
8082
);
8183

8284
@Inject

app/repository/EnrolmentRepository.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -288,6 +288,11 @@ private void handleUpcomingEnrolment(
288288
if (
289289
enrolment.getExam() != null && enrolment.getExam().getImplementation() == Exam.Implementation.AQUARIUM
290290
) {
291+
// If user is on a correct aquarium machine then always set a header
292+
headers.put(
293+
"x-exam-aquarium-login",
294+
String.format("%s:::%d", getExamHash(enrolment), enrolment.getId())
295+
);
291296
// Aquarium exam, don't set headers unless it starts in 5 minutes
292297
DateTime threshold = DateTime.now().plusMinutes(5);
293298
DateTime start = dateTimeHandler.normalize(

app/system/SystemFilter.scala

Lines changed: 11 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -12,48 +12,43 @@ import play.api.mvc.{Filter, RequestHeader, Result}
1212
import javax.inject.Inject
1313
import scala.concurrent.{ExecutionContext, Future}
1414

15-
object ResultImplicits {
16-
implicit class EnhancedResult(result: Result) {
17-
def discardingHeaders(headers: String*): Result =
18-
result.copy(header = result.header.copy(headers = result.header.headers -- headers))
19-
}
20-
}
21-
22-
class SystemFilter @Inject() (implicit val mat: Materializer, ec: ExecutionContext) extends Filter {
15+
class SystemFilter @Inject() (implicit val mat: Materializer, ec: ExecutionContext) extends Filter:
2316

2417
val Headers: Seq[(String, String)] = Seq(
2518
("x-exam-start-exam", "ongoingExamHash"),
2619
("x-exam-upcoming-exam", "upcomingExamHash"),
2720
("x-exam-wrong-machine", "wrongMachineData"),
2821
("x-exam-unknown-machine", "unknownMachineData"),
2922
("x-exam-wrong-room", "wrongRoomData"),
30-
("x-exam-wrong-agent-config", "wrongAgent")
23+
("x-exam-wrong-agent-config", "wrongAgent"),
24+
("x-exam-aquarium-login", "aquariumLogin")
3125
)
3226

33-
import ResultImplicits._
27+
extension (result: Result)
28+
private def discardingHeaders(headers: String*): Result =
29+
result.copy(header = result.header.copy(headers = result.header.headers -- headers))
3430

35-
private def processResult(src: Result)(implicit request: RequestHeader): Result = {
36-
val session = src.session match {
31+
private def processResult(src: Result)(implicit request: RequestHeader): Result =
32+
val session = src.session match
3733
case s if s.isEmpty =>
3834
request.session match {
3935
case rs if rs.isEmpty => None
4036
case rs => Some(rs)
4137
}
4238
case s => Some(s)
43-
}
4439
val result = src.withHeaders(
4540
("Cache-Control", "no-cache;no-store"),
4641
("Pragma", "no-cache"),
4742
("Expires", "0")
4843
)
49-
session match {
44+
session match
5045
case None => result.withNewSession
5146
case Some(s) =>
5247
val (remaining, discarded) = Headers.partition(h => s.get(h._2).isDefined)
5348
val response = result
5449
.withHeaders(remaining.map(h => (h._1, s.get(h._2).get))*)
5550
.discardingHeaders(discarded.map(_._1)*)
56-
request.path match {
51+
request.path match
5752
case path if path == "/app/session" && request.method == "GET" =>
5853
s.get("upcomingExamHash") match {
5954
case Some(_) => // Don't let session expire when awaiting exam to start
@@ -63,17 +58,11 @@ class SystemFilter @Inject() (implicit val mat: Materializer, ec: ExecutionConte
6358
case path if path.contains("logout") => response.withSession(s)
6459
case _ =>
6560
response.withSession(s + ("since" -> ISODateTimeFormat.dateTime.print(DateTime.now)))
66-
}
67-
}
68-
}
6961

7062
override def apply(next: RequestHeader => Future[Result])(rh: RequestHeader): Future[Result] =
71-
rh.path match {
63+
rh.path match
7264
case "/app/logout" => next.apply(rh)
7365
// Disable caching for index page so that CSRF cookie can be injected without worries
7466
case p if p.startsWith("/app") | p.startsWith("/integration") =>
7567
next.apply(rh).map(processResult(_)(rh))
7668
case _ => next.apply(rh).map(_.withHeaders(("Cache-Control", "no-cache")))
77-
}
78-
79-
}

scripts/internal/remove_overlapping.py

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,30 +5,34 @@
55
# SPDX-License-Identifier: EUPL-1.2
66

77
from datetime import datetime
8-
from psycopg2 import connect
8+
from psycopg import connect # pip install "psycopg[binary]"
99

1010
conn_string = "host='localhost' dbname='exam' user='exam' password='exam'"
1111
conn = connect(conn_string)
1212
cursor = conn.cursor()
1313

14-
def select(unique=False):
14+
15+
def select():
1516
names = [desc[0] for desc in cursor.description]
1617
result = map(dict, [[(names[i], row[i]) for (i, name) in enumerate(names)] for row in cursor])
17-
return list(result)[0] if unique else list(result)
18+
return list(result)
19+
1820

1921
def delete(ids):
2022
ids = ','.join([str(id) for id in ids])
2123
cursor.execute('UPDATE exam_enrolment SET reservation_id = NULL where reservation_id IN (%s)' % ids)
2224
cursor.execute('UPDATE exam_participation SET reservation_id = NULL where reservation_id IN (%s)' % ids)
2325
cursor.execute('DELETE FROM reservation WHERE id IN (%s)' % ids)
2426

27+
2528
def reservations():
2629
cursor.execute("""
2730
SELECT r.*, ep.id AS ep_id FROM reservation AS r
2831
LEFT JOIN exam_participation AS ep ON ep.reservation_id = r.id WHERE r.machine_id IS NOT NULL
2932
""")
3033
return select()
3134

35+
3236
def find_overlapping(rs):
3337
overlapping_pairs = []
3438
rs.sort(key=lambda x: (x["machine_id"], x["start_at"]))
@@ -43,13 +47,16 @@ def find_overlapping(rs):
4347
overlapping_pairs.append((res1, res2))
4448
return overlapping_pairs
4549

50+
4651
def main():
47-
print("Following overlapping reservation pairs found:")
4852
rs, removed, unresolved = reservations(), set(), set()
53+
print("Following overlapping reservation pairs found:")
4954
for r1, r2 in find_overlapping(rs):
50-
print("r1_id: {id1} r2_id:{id2} r1_machine_id: {mid1} r2_machine_id: {mid2} r1_period: {s1} - {e1} r2_period {s2} - {e2}".format(
51-
id1=r1['id'], id2=r2['id'], mid1=r1['machine_id'], mid2=r2['machine_id'], s1=r1['start_at'], e1=r1['end_at'], s2=r2['start_at'], e2=r2['end_at']
52-
))
55+
print(
56+
"r1_id: {id1} r2_id:{id2} r1_machine_id: {mid1} r2_machine_id: {mid2} r1_period: {s1} - {e1} r2_period {s2} - {e2}".format(
57+
id1=r1['id'], id2=r2['id'], mid1=r1['machine_id'], mid2=r2['machine_id'], s1=r1['start_at'],
58+
e1=r1['end_at'], s2=r2['start_at'], e2=r2['end_at']
59+
))
5360
if r1['ep_id'] and not r2['ep_id']:
5461
print('Reservation #%s will be removed' % r2['id'])
5562
removed.add(r2['id'])
@@ -61,7 +68,8 @@ def main():
6168
print('Reservation #%s will be removed' % r2['id'])
6269
removed.update([r1['id'], r2['id']])
6370
else:
64-
print('Cannot automatically remove reservations #%s and #%s' % (r1['id'], r2['id']))
71+
print('Will not automatically remove reservations #%s and #%s as both are linked to some participation'
72+
% (r1['id'], r2['id']))
6573
unresolved.update([r1['id'], r2['id']])
6674
print('Conclusion')
6775
print('The following reservations will be removed: \n%s' % removed)
@@ -70,5 +78,6 @@ def main():
7078
delete(removed)
7179
conn.commit()
7280

81+
7382
if __name__ == "__main__":
7483
main()

ui/src/app/administrative/reports/categories/answers-report.component.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
// SPDX-License-Identifier: EUPL-1.2
44

55
import { Component } from '@angular/core';
6-
import { NgbPopover } from '@ng-bootstrap/ng-bootstrap';
76
import { TranslateModule } from '@ngx-translate/core';
87
import { format } from 'date-fns';
98
import { DatePickerComponent } from 'src/app/shared/date/date-picker.component';
@@ -39,7 +38,7 @@ import { FileService } from 'src/app/shared/file/file.service';
3938
`,
4039
selector: 'xm-answers-report',
4140
standalone: true,
42-
imports: [DatePickerComponent, NgbPopover, TranslateModule],
41+
imports: [DatePickerComponent, TranslateModule],
4342
})
4443
export class AnswersReportComponent {
4544
startDate: Date | null = null;

ui/src/app/administrative/reports/categories/enrolments-report.component.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
// SPDX-License-Identifier: EUPL-1.2
44

55
import { Component, Input } from '@angular/core';
6-
import { NgbPopover } from '@ng-bootstrap/ng-bootstrap';
76
import { TranslateModule, TranslateService } from '@ngx-translate/core';
87
import { ToastrService } from 'ngx-toastr';
98
import { FileService } from 'src/app/shared/file/file.service';
@@ -36,7 +35,7 @@ import { Option } from 'src/app/shared/select/select.model';
3635
`,
3736
selector: 'xm-enrolments-report',
3837
standalone: true,
39-
imports: [DropdownSelectComponent, NgbPopover, TranslateModule],
38+
imports: [DropdownSelectComponent, TranslateModule],
4039
})
4140
export class EnrolmentsReportComponent {
4241
@Input() examNames: Option<string, number>[] = [];

ui/src/app/administrative/reports/categories/exams-report.component.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
// SPDX-License-Identifier: EUPL-1.2
44

55
import { Component, Input } from '@angular/core';
6-
import { NgbPopover } from '@ng-bootstrap/ng-bootstrap';
76
import { TranslateModule, TranslateService } from '@ngx-translate/core';
87
import { ToastrService } from 'ngx-toastr';
98
import { FileService } from 'src/app/shared/file/file.service';
@@ -39,7 +38,7 @@ import { Option } from 'src/app/shared/select/select.model';
3938
`,
4039
selector: 'xm-exams-report',
4140
standalone: true,
42-
imports: [DropdownSelectComponent, NgbPopover, TranslateModule],
41+
imports: [DropdownSelectComponent, TranslateModule],
4342
})
4443
export class ExamsReportComponent {
4544
@Input() examNames: Option<string, number>[] = [];

ui/src/app/administrative/reports/categories/records-report.component.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
// SPDX-License-Identifier: EUPL-1.2
44

55
import { Component } from '@angular/core';
6-
import { NgbPopover } from '@ng-bootstrap/ng-bootstrap';
76
import { TranslateModule } from '@ngx-translate/core';
87
import { DatePickerComponent } from 'src/app/shared/date/date-picker.component';
98
import { FileService } from 'src/app/shared/file/file.service';
@@ -38,7 +37,7 @@ import { FileService } from 'src/app/shared/file/file.service';
3837
`,
3938
selector: 'xm-records-report',
4039
standalone: true,
41-
imports: [DatePickerComponent, NgbPopover, TranslateModule],
40+
imports: [DatePickerComponent, TranslateModule],
4241
})
4342
export class RecordsReportComponent {
4443
startDate: Date | null = null;

ui/src/app/administrative/reports/categories/reviews-report.component.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
// SPDX-License-Identifier: EUPL-1.2
44

55
import { Component } from '@angular/core';
6-
import { NgbPopover } from '@ng-bootstrap/ng-bootstrap';
76
import { TranslateModule } from '@ngx-translate/core';
87
import { format } from 'date-fns';
98
import { DatePickerComponent } from 'src/app/shared/date/date-picker.component';
@@ -38,7 +37,7 @@ import { FileService } from 'src/app/shared/file/file.service';
3837
`,
3938
selector: 'xm-reviews-report',
4039
standalone: true,
41-
imports: [DatePickerComponent, NgbPopover, TranslateModule],
40+
imports: [DatePickerComponent, TranslateModule],
4241
})
4342
export class ReviewsReportComponent {
4443
startDate: Date | null = null;

ui/src/app/administrative/reports/categories/rooms-report.component.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
// SPDX-License-Identifier: EUPL-1.2
44

55
import { Component, Input } from '@angular/core';
6-
import { NgbPopover } from '@ng-bootstrap/ng-bootstrap';
76
import { TranslateModule, TranslateService } from '@ngx-translate/core';
87
import { format } from 'date-fns';
98
import { ToastrService } from 'ngx-toastr';
@@ -53,7 +52,7 @@ import { Option } from 'src/app/shared/select/select.model';
5352
`,
5453
selector: 'xm-rooms-report',
5554
standalone: true,
56-
imports: [DropdownSelectComponent, DatePickerComponent, NgbPopover, TranslateModule],
55+
imports: [DropdownSelectComponent, DatePickerComponent, TranslateModule],
5756
})
5857
export class RoomsReportComponent {
5958
@Input() rooms: Option<ExamRoom, number>[] = [];

0 commit comments

Comments
 (0)