Skip to content

Commit 6b4adfb

Browse files
committed
[Api+Web] Allow student-leads to register new students
1 parent e5ee65b commit 6b4adfb

File tree

7 files changed

+26
-14
lines changed

7 files changed

+26
-14
lines changed

attendance-api/database/seeders/RolesSeeder.php

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,9 +69,12 @@ public function run()
6969
Role::create(['name' => 'student-lead'])
7070
->givePermissionTo([
7171
'list students',
72+
'add students',
73+
'view student images',
74+
'modify students',
75+
'modify student images',
7276
'list attendance events',
7377
'student check in',
74-
'view student images',
7578
'undo attendance event',
7679
'list users',
7780
'list roles',

attendance-web/src/app/app-routing.module.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ const routes: Routes = [
3030
{path: 'detail/:studentId', component: ShowStudentComponent},
3131
{ path: 'edit/:studentId', component: UpdateOrCreateStudentComponent,
3232
canActivate: [MustHavePermissionGuard],
33-
data: { permissions: ['modify students', 'modify student images', 'remove students'] }},
33+
data: { permissions: ['modify students', 'modify student images'] }},
3434
{path: 'list', component: ListStudentsComponent},
3535
{path: 'add', component: UpdateOrCreateStudentComponent,
3636
canActivate: [MustHavePermissionGuard],

attendance-web/src/app/components/students/show-student/show-student.component.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ <h1 id="studentNotFound">404: Student not found</h1>
1515
<mat-icon id="deletedIndicator">delete</mat-icon>
1616
}
1717
<h1>{{ student.name }}</h1>
18-
@if (canDelete()|async) {
18+
@if (mayEditStudent()|async) {
1919
<div><a mat-raised-button color="primary" [routerLink]="['/', 'students', 'edit', student.id]">Edit</a></div>
2020
}
2121
</div>

attendance-web/src/app/components/students/show-student/show-student.component.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -171,8 +171,8 @@ export class ShowStudentComponent implements OnInit, OnDestroy {
171171
return this.student.pipe(map(student => student.deleted_at != null));
172172
}
173173

174-
canDelete(): Observable<boolean> {
175-
return this.permissionsService.checkPermissions(['modify students', 'modify student images', 'remove students']);
174+
mayEditStudent(): Observable<boolean> {
175+
return this.permissionsService.checkPermissions(['modify students', 'modify student images']);
176176
}
177177

178178
getProfileImageSrc(student: Student): string {

attendance-web/src/app/components/students/students.component.ts

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { Component } from '@angular/core';
2-
import { Observable, ReplaySubject, map } from 'rxjs';
3-
import { AuthService } from 'src/app/services/auth.service';
2+
import { ReplaySubject } from 'rxjs';
3+
import { PermissionsService } from 'src/app/services/permissions.service';
44

55
interface Tab {
66
path: string;
@@ -17,17 +17,18 @@ export class StudentsComponent {
1717
tabs = new ReplaySubject<Tab[]>(1);
1818

1919
constructor(
20-
authService: AuthService
20+
permissionsService: PermissionsService
2121
) {
22-
authService.getUser().subscribe(user => {
22+
23+
permissionsService.checkPermissions(["add students"]).subscribe(userMayAddStudents => {
2324
let tabs: Tab[] = [
2425
{
2526
path: './list',
2627
name: 'List Students',
2728
}
2829
];
2930

30-
if(user?.role_names.includes("mentor")) {
31+
if(userMayAddStudents) {
3132
tabs.push({
3233
path: './add',
3334
name: 'Add Student'

attendance-web/src/app/components/students/update-or-create-student/update-or-create-student.component.html

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,21 +9,21 @@ <h1>Student not found!</h1>
99
<ng-container *ngTemplateOutlet="student_details"></ng-container>
1010
}
1111
@case (stateType.LOADED) {
12+
<ng-container *ngTemplateOutlet="student_details"></ng-container>
1213
<mat-card>
13-
<mat-card-header>Student Actions</mat-card-header>
14+
<mat-card-header>Actions</mat-card-header>
1415
<mat-card-content>
1516
@if (editStudent|async; as student) {
1617
<div class="actionRow">
1718
@if (this.isDeleted|async) {
18-
<button mat-raised-button color="primary" (click)="undoDelete(student)">Restore Student</button>
19+
<button [disabled]="userMayNotDeleteStudents|async" mat-raised-button color="primary" (click)="undoDelete(student)">Restore Student</button>
1920
} @else {
20-
<button mat-raised-button color="warn" (click)="doDelete(student)">Delete Student</button>
21+
<button [disabled]="userMayNotDeleteStudents|async" mat-raised-button color="warn" (click)="doDelete(student)">Delete Student</button>
2122
}
2223
</div>
2324
}
2425
</mat-card-content>
2526
</mat-card>
26-
<ng-container *ngTemplateOutlet="student_details"></ng-container>
2727
}
2828
}
2929

attendance-web/src/app/components/students/update-or-create-student/update-or-create-student.component.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import { ActivatedRoute, Router } from '@angular/router';
77
import { DateTime } from 'luxon';
88
import { BehaviorSubject, concatMap, filter, forkJoin, map, Observable, ReplaySubject, Subject, Subscription, take, takeUntil } from 'rxjs';
99
import { Student } from 'src/app/models/student.model';
10+
import { PermissionsService } from 'src/app/services/permissions.service';
1011
import { ProfileImagesService, UploadStatus } from 'src/app/services/profile-images.service';
1112
import { StudentsService } from 'src/app/services/students.service';
1213
import { environment } from 'src/environments/environment';
@@ -35,6 +36,8 @@ export class UpdateOrCreateStudentComponent implements OnInit, OnDestroy {
3536
protected state: BehaviorSubject<ComponentState>
3637
private students : Observable<Array<Student>>
3738

39+
protected userMayNotDeleteStudents: Observable<boolean>
40+
3841
editStudent = new ReplaySubject<Student|null>(1)
3942
isDeleted: Observable<Boolean>
4043

@@ -51,17 +54,22 @@ export class UpdateOrCreateStudentComponent implements OnInit, OnDestroy {
5154
private snackBar: MatSnackBar,
5255
private router: Router,
5356
private profilePhotosService: ProfileImagesService,
57+
private permissionsService: PermissionsService,
5458
private dialog: MatDialog,
5559
route: ActivatedRoute) {
5660
let id = route.snapshot.paramMap.get('studentId');
5761
this.students = this.studentsService.getAllStudents(true);
62+
63+
this.userMayNotDeleteStudents = permissionsService.checkPermissions(["remove students"]).pipe(map(it => !it));
64+
5865
if(route.snapshot.url[0].path == 'edit' && id != null) {
5966
let parsedId = parseInt(id);
6067
this.students.pipe(takeUntil(this.unsubscribe), map( (students: Array<Student>) => {
6168
return students.find(it => it.id == parsedId) ?? null;
6269
})).subscribe(this.editStudent);
6370

6471
this.state = new BehaviorSubject<ComponentState>(ComponentState.LOADING_STUDENT);
72+
6573
this.editStudent.pipe(map(student => {
6674
if(student != null) {
6775
return ComponentState.LOADED;

0 commit comments

Comments
 (0)