Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

General: Migrate suspicious behavior module to signals, inject and standalone #9887

Open
wants to merge 6 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,12 @@ <h5 jhiTranslate="artemisApp.examManagement.plagiarismCasesOverview.title"></h5>
</tr>
</thead>
<tbody>
@for (exercise of exercises; track exercise; let i = $index) {
@for (exercise of exercises(); track exercise; let i = $index) {
<tr>
<th scope="row">{{ i + 1 }}</th>
<td>{{ exercise.title }}</td>
<td>{{ plagiarismResultsPerExercise.get(exercise) }}</td>
<td>{{ plagiarismCasesPerExercise.get(exercise) }}</td>
<td>{{ plagiarismResultsPerExercise().get(exercise) }}</td>
<td>{{ plagiarismCasesPerExercise().get(exercise) }}</td>
<td>
<button
id="view-plagiarism-results-btn-{{ i }}"
Expand All @@ -28,7 +28,7 @@ <h5 jhiTranslate="artemisApp.examManagement.plagiarismCasesOverview.title"></h5>
}
</tbody>
</table>
@if (anyPlagiarismCases) {
@if (anyPlagiarismCases()) {
<button
class="btn btn-primary"
id="view-plagiarism-cases-btn"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Component, Input } from '@angular/core';
import { Component, inject, input } from '@angular/core';
import { Exercise, getExerciseUrlSegment } from 'app/entities/exercise.model';
import { Router } from '@angular/router';

Expand All @@ -7,22 +7,23 @@ import { Router } from '@angular/router';
templateUrl: './plagiarism-cases-overview.component.html',
})
export class PlagiarismCasesOverviewComponent {
@Input() exercises: Exercise[];
@Input() plagiarismCasesPerExercise: Map<Exercise, number>;
@Input() plagiarismResultsPerExercise: Map<Exercise, number> = new Map<Exercise, number>();
@Input() anyPlagiarismCases = false;
@Input() courseId: number;
@Input() examId: number;
constructor(private router: Router) {}
private router = inject(Router);

exercises = input.required<Exercise[]>();
plagiarismCasesPerExercise = input.required<Map<Exercise, number>>();
plagiarismResultsPerExercise = input.required<Map<Exercise, number>>();
anyPlagiarismCases = input(false);
courseId = input.required<number>();
examId = input.required<number>();

goToPlagiarismDetection(exercise: Exercise) {
const exerciseGroupId = exercise.exerciseGroup?.id;
const exerciseType = exercise.type;
this.router.navigate([
'/course-management',
this.courseId,
this.courseId(),
'exams',
this.examId,
this.examId(),
'exercise-groups',
exerciseGroupId,
getExerciseUrlSegment(exerciseType),
Expand All @@ -31,6 +32,6 @@ export class PlagiarismCasesOverviewComponent {
]);
}
goToPlagiarismCases() {
this.router.navigate(['/course-management', this.courseId, 'exams', this.examId, 'plagiarism-cases']);
this.router.navigate(['/course-management', this.courseId(), 'exams', this.examId(), 'plagiarism-cases']);
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Component, OnInit, ViewChild } from '@angular/core';
import { Component, OnInit, ViewChild, inject } from '@angular/core';
import { Exercise } from 'app/entities/exercise.model';
import { SuspiciousExamSessions, SuspiciousSessionsAnalysisOptions } from 'app/entities/exam/exam-session.model';
import { SuspiciousSessionsService } from 'app/exam/manage/suspicious-behavior/suspicious-sessions.service';
Expand All @@ -14,6 +14,13 @@ import { DocumentationType } from 'app/shared/components/documentation-button/do
templateUrl: './suspicious-behavior.component.html',
})
export class SuspiciousBehaviorComponent implements OnInit {
private suspiciousSessionsService = inject(SuspiciousSessionsService);
private activatedRoute = inject(ActivatedRoute);
private plagiarismCasesService = inject(PlagiarismCasesService);
private examService = inject(ExamManagementService);
private plagiarismResultsService = inject(PlagiarismResultsService);
private router = inject(Router);

@ViewChild('analysis', { static: false }) analysisForm: NgForm;

exercises: Exercise[] = [];
Expand All @@ -40,15 +47,6 @@ export class SuspiciousBehaviorComponent implements OnInit {

readonly documentationType: DocumentationType = 'SuspiciousBehavior';

constructor(
private suspiciousSessionsService: SuspiciousSessionsService,
private activatedRoute: ActivatedRoute,
private plagiarismCasesService: PlagiarismCasesService,
private examService: ExamManagementService,
private plagiarismResultsService: PlagiarismResultsService,
private router: Router,
) {}

ngOnInit(): void {
this.examId = Number(this.activatedRoute.snapshot.paramMap.get('examId'));
this.courseId = Number(this.activatedRoute.snapshot.paramMap.get('courseId'));
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import { HttpClient, HttpParams } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { Injectable, inject } from '@angular/core';
import { SuspiciousExamSessions, SuspiciousSessionsAnalysisOptions } from 'app/entities/exam/exam-session.model';
import { Observable } from 'rxjs';

@Injectable({
providedIn: 'root',
})
export class SuspiciousSessionsService {
constructor(private http: HttpClient) {}
private http = inject(HttpClient);

getSuspiciousSessions(courseId: number, examId: number, options: SuspiciousSessionsAnalysisOptions): Observable<SuspiciousExamSessions[]> {
let params = new HttpParams()
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
@for (session of suspiciousSessions.examSessions; track session; let i = $index) {
@for (session of suspiciousSessions().examSessions; track session; let i = $index) {
<tr>
<th scope="row">{{ session.id }}</th>
<td [ngClass]="suspiciousFingerprint ? 'suspicious' : ''">{{ session.browserFingerprintHash }}</td>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Component, Input, OnInit } from '@angular/core';
import { Component, OnInit, input } from '@angular/core';
import { SuspiciousExamSessions, SuspiciousSessionReason } from 'app/entities/exam/exam-session.model';
import { StudentExam } from 'app/entities/student-exam.model';

Expand All @@ -10,7 +10,7 @@ import { StudentExam } from 'app/entities/student-exam.model';
styleUrls: ['./suspicious-sessions.component.scss'],
})
export class SuspiciousSessionsComponent implements OnInit {
@Input() suspiciousSessions: SuspiciousExamSessions;
suspiciousSessions = input.required<SuspiciousExamSessions>();
suspiciousFingerprint = false;
suspiciousIpAddress = false;
ngOnInit(): void {
Expand All @@ -31,6 +31,6 @@ export class SuspiciousSessionsComponent implements OnInit {
}

private isSuspiciousFor(reason: SuspiciousSessionReason) {
return this.suspiciousSessions.examSessions.some((session) => session.suspiciousReasons.includes(reason));
return this.suspiciousSessions().examSessions.some((session) => session.suspiciousReasons.includes(reason));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import { MockRouter } from '../../../../helpers/mocks/mock-router';
import { Exercise } from 'app/entities/exercise.model';

describe('PlagiarismCasesOverviewComponent', () => {
let component: PlagiarismCasesOverviewComponent;
let fixture: ComponentFixture<PlagiarismCasesOverviewComponent>;
let router: Router;
const exercise1 = {
Expand Down Expand Up @@ -49,32 +48,38 @@ describe('PlagiarismCasesOverviewComponent', () => {
],
});
fixture = TestBed.createComponent(PlagiarismCasesOverviewComponent);
component = fixture.componentInstance;
router = TestBed.inject(Router);
component.courseId = 1;
component.examId = 2;
component.exercises = [exercise1, exercise2];
component.plagiarismCasesPerExercise = new Map([
[exercise1, 0],
[exercise2, 1],
]);
component.plagiarismResultsPerExercise = new Map([
[exercise1, 2],
[exercise2, 4],
]);
fixture.componentRef.setInput('courseId', 1);
fixture.componentRef.setInput('examId', 2);
fixture.componentRef.setInput('exercises', [exercise1, exercise2]);
fixture.componentRef.setInput(
'plagiarismCasesPerExercise',
new Map([
[exercise1, 0],
[exercise2, 1],
]),
);
fixture.componentRef.setInput(
'plagiarismResultsPerExercise',
new Map([
[exercise1, 2],
[exercise2, 4],
]),
);

fixture.detectChanges();
});

it('should navigate to plagiarism cases on view plagiarism cases click', () => {
component.anyPlagiarismCases = true;
fixture.componentRef.setInput('anyPlagiarismCases', true);
fixture.detectChanges();
const viewCasesButton = fixture.debugElement.nativeElement.querySelector('#view-plagiarism-cases-btn');
viewCasesButton.click();
expect(router.navigate).toHaveBeenCalledWith(['/course-management', 1, 'exams', 2, 'plagiarism-cases']);
});

it('should not show view cases button if no cases exist', () => {
component.anyPlagiarismCases = false;
fixture.componentRef.setInput('anyPlagiarismCases', false);
fixture.detectChanges();
const viewCasesButton = fixture.debugElement.nativeElement.querySelector('#view-plagiarism-cases-btn');
expect(viewCasesButton).toBeNull();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,24 +43,24 @@ describe('SuspiciousSessionsComponent', () => {
});
fixture = TestBed.createComponent(SuspiciousSessionsComponent);
component = fixture.componentInstance;
component.suspiciousSessions = suspiciousSessions1;
fixture.componentRef.setInput('suspiciousSessions', suspiciousSessions1);
});

it('should contain correct link to student exam in table cell', () => {
expect(component.getStudentExamLink(studentExam)).toBe('/course-management/1/exams/1/student-exams/1');
});

it('should correctly determine suspicious reasons', () => {
component.suspiciousSessions = suspiciousSessions1;
fixture.componentRef.setInput('suspiciousSessions', suspiciousSessions1);
component.ngOnInit();
expect(component.suspiciousFingerprint).toBeTrue();
expect(component.suspiciousIpAddress).toBeTrue();

component.suspiciousSessions = suspiciousSessions2;
fixture.componentRef.setInput('suspiciousSessions', suspiciousSessions2);
component.ngOnInit();
expect(component.suspiciousFingerprint).toBeFalse();
expect(component.suspiciousIpAddress).toBeFalse();
component.suspiciousSessions = suspiciousSessions3;
fixture.componentRef.setInput('suspiciousSessions', suspiciousSessions3);
component.ngOnInit();
expect(component.suspiciousFingerprint).toBeFalse();
expect(component.suspiciousIpAddress).toBeTrue();
Expand Down
Loading