Skip to content

Commit

Permalink
CSCEXAM-1237 Permission for creating BYOD exams
Browse files Browse the repository at this point in the history
  • Loading branch information
Matti Lupari committed Jan 11, 2024
1 parent e31b9f2 commit f7f9ec8
Show file tree
Hide file tree
Showing 15 changed files with 60 additions and 17 deletions.
7 changes: 7 additions & 0 deletions app/controllers/ExamController.java
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
import models.ExamType;
import models.GradeScale;
import models.Language;
import models.Permission;
import models.Role;
import models.Software;
import models.User;
Expand Down Expand Up @@ -494,6 +495,12 @@ public Result createExamDraft(Http.Request request) {
return badRequest("Unsupported execution type");
}
User user = request.attrs().get(Attrs.AUTHENTICATED_USER);
if (
implementation != Exam.Implementation.AQUARIUM.toString() &&
!user.hasPermission(Permission.Type.CAN_CREATE_BYOD_EXAM)
) {
return forbidden("No permission to create home examinations");
}
Exam exam = new Exam();
exam.generateHash();
exam.setState(Exam.State.DRAFT);
Expand Down
2 changes: 2 additions & 0 deletions app/models/Permission.java
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ public class Permission extends GeneratedIdentityModel implements be.objectify.d
public enum Type {
@EnumValue("1")
CAN_INSPECT_LANGUAGE,
@EnumValue("2")
CAN_CREATE_BYOD_EXAM,
}

private Type type;
Expand Down
2 changes: 2 additions & 0 deletions conf/application.conf
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,8 @@ exam.user.studentIds.multiple.organisations = "org1.org,org2.org,org3.org"
exam.byod.seb.active = false
# Enable / disable support for unsupervised home examination
exam.byod.home.active = false
# Require special permission for being able to create BYOD examinations
exam.byod.permission = false
# Maximum number of concurrent BYOD examination participants
exam.byod.maxConcurrentParticipants = 100000
# SEB configuration
Expand Down
1 change: 1 addition & 0 deletions conf/dev.conf
Original file line number Diff line number Diff line change
Expand Up @@ -32,4 +32,5 @@ play.evolutions.db.default.autocommit = false

exam.byod.seb.active = true
exam.byod.home.active = true
exam.byod.permission = true
exam.exam.seb.quitPwd = "quit now"
5 changes: 5 additions & 0 deletions conf/evolutions/default/132.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# --- !Ups
INSERT INTO permission (id, object_version, type, description) VALUES (2, 1, 2, 'can create BYOD exams')

# --- !Downs
DELETE FROM permission where id = 2;
11 changes: 6 additions & 5 deletions ui/src/app/administrative/users/users.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@
</button>
</div>
</span>
<!-- ng-show="permissions.length > 0" -->

<span class="dropdown" ngbDropdown>
<button
ngbDropdownToggle
Expand Down Expand Up @@ -124,9 +124,9 @@
<td>{{ user.employeeNumber }}</td>
<td>{{ user.lastLogin | date : 'dd.MM.yyyy HH:mm:ss' }}</td>
<td>
<i *ngIf="hasRole(user, 'ADMIN')" class="bi-gear-fill"></i>
<i *ngIf="hasRole(user, 'TEACHER')" class="bi-person-fill"></i>
<i *ngIf="hasRole(user, 'STUDENT')" class="bi-person"></i>
<i *ngIf="hasRole(user, 'ADMIN')" class="bi-gear-fill pe-1"></i>
<i *ngIf="hasRole(user, 'TEACHER')" class="bi-person pe-1"></i>
<i *ngIf="hasRole(user, 'STUDENT')" class="bi-mortarboard pe-1"></i>

<div class="float-end">
<span class="no-caret pointer" ngbDropdown>
Expand Down Expand Up @@ -199,7 +199,8 @@
</div>
</td>
<td>
<i *ngIf="hasPermission(user, 'CAN_INSPECT_LANGUAGE')" class="bi-pencil"></i>
<i *ngIf="hasPermission(user, 'CAN_INSPECT_LANGUAGE')" class="bi-alphabet pe-1"></i>
<i *ngIf="hasPermission(user, 'CAN_CREATE_BYOD_EXAM')" class="bi-house-gear pe-1"></i>

<div class="float-end">
<span class="no-caret" ngbDropdown>
Expand Down
13 changes: 10 additions & 3 deletions ui/src/app/administrative/users/users.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,8 +69,8 @@ export class UsersComponent implements OnInit, OnDestroy {
ngUnsubscribe = new Subject();
roles: RoleOption[] = [
{ type: 'ADMIN', name: 'i18n_admin', icon: 'bi-gear' },
{ type: 'TEACHER', name: 'i18n_teacher', icon: 'bi-person-fill' },
{ type: 'STUDENT', name: 'i18n_student', icon: 'bi-person' },
{ type: 'TEACHER', name: 'i18n_teacher', icon: 'bi-person' },
{ type: 'STUDENT', name: 'i18n_student', icon: 'bi-mortarboard' },
];
permissions: PermissionOption[] = [];
loader = { loading: false };
Expand Down Expand Up @@ -101,7 +101,14 @@ export class UsersComponent implements OnInit, OnDestroy {
return {
...p,
name: 'i18n_can_inspect_language',
icon: 'bi-pencil',
icon: 'bi-alphabet',
};
}
if (p.type === PermissionType.CAN_CREATE_BYOD_EXAM) {
return {
...p,
name: 'i18n_can_create_byod_exam',
icon: 'bi-house-gear',
};
}

Expand Down
1 change: 1 addition & 0 deletions ui/src/app/administrative/users/users.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import type { Role, User } from '../../session/session.service';

export enum PermissionType {
CAN_INSPECT_LANGUAGE = 'CAN_INSPECT_LANGUAGE',
CAN_CREATE_BYOD_EXAM = 'CAN_CREATE_BYOD_EXAM',
}

export interface Permission {
Expand Down
12 changes: 10 additions & 2 deletions ui/src/app/exam/editor/creation/new-exam.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -78,10 +78,18 @@
required
>
<option value="AQUARIUM">{{ 'i18n_examination_type_aquarium' | translate }}</option>
<option *ngIf="sebExaminationSupported" value="CLIENT_AUTH">
<option
*ngIf="sebExaminationSupported"
[disabled]="!canCreateByodExams"
value="CLIENT_AUTH"
>
{{ 'i18n_examination_type_seb' | translate }}
</option>
<option *ngIf="homeExaminationSupported" value="WHATEVER">
<option
*ngIf="homeExaminationSupported"
[disabled]="!canCreateByodExams"
value="WHATEVER"
>
{{ 'i18n_examination_type_home_exam' | translate }}
</option>
</select>
Expand Down
5 changes: 4 additions & 1 deletion ui/src/app/exam/editor/creation/new-exam.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import { Component } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { NgbPopover } from '@ng-bootstrap/ng-bootstrap';
import { TranslateModule } from '@ngx-translate/core';
import { SessionService } from 'src/app/session/session.service';
import { HistoryBackComponent } from '../../../shared/history/history-back.component';
import type { ExamExecutionType, Implementation } from '../../exam.model';
import { ExamService } from '../../exam.service';
Expand All @@ -35,10 +36,12 @@ export class NewExamComponent implements OnInit {
examinationType: Implementation = 'AQUARIUM';
homeExaminationSupported = false;
sebExaminationSupported = false;
canCreateByodExams = false;

constructor(private http: HttpClient, private Exam: ExamService) {}
constructor(private http: HttpClient, private Exam: ExamService, private Session: SessionService) {}

ngOnInit() {
this.canCreateByodExams = this.Session.getUser().canCreateByodExam;
this.Exam.listExecutionTypes$().subscribe((types) => {
this.executionTypes = types;
this.http
Expand Down
2 changes: 1 addition & 1 deletion ui/src/app/session/role/role-picker-dialog.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ import type { User } from '../session.service';
title="{{ role.displayName || '' | translate }}"
(click)="activeModal.close(role)"
>
{{ role.displayName || '' | translate }} <i [ngClass]="role.icon || ''"></i>
{{ role.displayName || '' | translate }} <i class="ps-1" [ngClass]="role.icon"></i>
</button>
</div>
</div>
Expand Down
7 changes: 5 additions & 2 deletions ui/src/app/session/session.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ export interface User {
isLanguageInspector: boolean;
employeeNumber: string | null;
lastLogin: string | null;
canCreateByodExam: boolean;
}

interface Env {
Expand Down Expand Up @@ -245,6 +246,7 @@ export class SessionService implements OnDestroy {
user.isTeacher = role.name === 'TEACHER';
user.isStudent = role.name === 'STUDENT';
user.isLanguageInspector = user.isTeacher && this.hasPermission(user, 'CAN_INSPECT_LANGUAGE');
user.canCreateByodExam = !user.isStudent && this.hasPermission(user, 'CAN_CREATE_BYOD_EXAM');
return user;
}),
);
Expand All @@ -259,11 +261,11 @@ export class SessionService implements OnDestroy {
break;
case 'TEACHER':
role.displayName = 'i18n_teacher';
role.icon = 'bi-person-fill';
role.icon = 'bi-person';
break;
case 'STUDENT':
role.displayName = 'i18n_student';
role.icon = 'bi-person';
role.icon = 'bi-mortarboard';
break;
}
});
Expand All @@ -278,6 +280,7 @@ export class SessionService implements OnDestroy {
isAdmin: loginRole != null && loginRole === 'ADMIN',
isStudent: loginRole != null && loginRole === 'STUDENT',
isLanguageInspector: isTeacher && this.hasPermission(user, 'CAN_INSPECT_LANGUAGE'),
canCreateByodExam: loginRole !== 'STUDENT' && this.hasPermission(user, 'CAN_CREATE_BYOD_EXAM'),
})),
);
}
Expand Down
3 changes: 2 additions & 1 deletion ui/src/assets/i18n/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -1158,5 +1158,6 @@
"i18n_preview_question": "Question Preview",
"i18n_button_preview": "Preview question",
"i18n_no_preview_available": "No preview available",
"i18n_used_in_exams": "Used in exams"
"i18n_used_in_exams": "Used in exams",
"i18n_can_create_byod_exam": "Voi luoda omakonetentin EN"
}
3 changes: 2 additions & 1 deletion ui/src/assets/i18n/fi.json
Original file line number Diff line number Diff line change
Expand Up @@ -1158,5 +1158,6 @@
"i18n_preview_question": "Kysymyksen esikatselu",
"i18n_button_preview": "Esikatsele kysymys",
"i18n_no_preview_available": "Kysymyksen esikatselu ei ole saatavilla",
"i18n_used_in_exams": "Käytössä tenteissä"
"i18n_used_in_exams": "Käytössä tenteissä",
"i18n_can_create_byod_exam": "Voi luoda omakonetentin"
}
3 changes: 2 additions & 1 deletion ui/src/assets/i18n/sv.json
Original file line number Diff line number Diff line change
Expand Up @@ -1158,5 +1158,6 @@
"i18n_preview_question": "Question Preview SV",
"i18n_button_preview": "Preview question SV",
"i18n_no_preview_available": "No preview available SV",
"i18n_used_in_exams": "Käytössä tenteissä SV"
"i18n_used_in_exams": "Käytössä tenteissä SV",
"i18n_can_create_byod_exam": "Voi luoda omakonetentin SV"
}

0 comments on commit f7f9ec8

Please sign in to comment.