Skip to content

Commit

Permalink
Exam mode: Show exercise group title in breadcrumbs (#9254)
Browse files Browse the repository at this point in the history
  • Loading branch information
Strohgelaender authored and JohannesWt committed Sep 23, 2024
1 parent 41080d2 commit f70a3d2
Show file tree
Hide file tree
Showing 6 changed files with 50 additions and 31 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -676,7 +676,7 @@ export class CourseManagementService {
this.entityTitleService.setTitle(EntityType.COURSE, [course?.id], course?.title);

course?.exercises?.forEach((exercise) => {
this.entityTitleService.setTitle(EntityType.EXERCISE, [exercise.id], exercise.title);
this.entityTitleService.setExerciseTitle(exercise);
});
course?.lectures?.forEach((lecture) => this.entityTitleService.setTitle(EntityType.LECTURE, [lecture.id], lecture.title));
course?.exams?.forEach((exam) => this.entityTitleService.setTitle(EntityType.EXAM, [exam.id], exam.title));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@ import { Injectable } from '@angular/core';
import { AccountService } from 'app/core/auth/account.service';
import { Participation } from 'app/entities/participation/participation.model';
import { ProgrammingExerciseStudentParticipation } from 'app/entities/participation/programming-exercise-student-participation.model';
import { CommitInfo } from 'app/entities/programming/programming-submission.model';
import { Result } from 'app/entities/result.model';
import { EntityTitleService, EntityType } from 'app/shared/layouts/navbar/entity-title.service';
import { createRequestOption } from 'app/shared/util/request.util';
import { Observable, map, tap } from 'rxjs';
import { CommitInfo } from 'app/entities/programming/programming-submission.model';

export interface IProgrammingExerciseParticipationService {
getLatestResultWithFeedback: (participationId: number, withSubmission: boolean) => Observable<Result | undefined>;
Expand Down Expand Up @@ -81,7 +81,7 @@ export class ProgrammingExerciseParticipationService implements IProgrammingExer
sendTitlesToEntityTitleService(participation: Participation | undefined) {
if (participation?.exercise) {
const exercise = participation.exercise;
this.entityTitleService.setTitle(EntityType.EXERCISE, [exercise.id], exercise.title);
this.entityTitleService.setExerciseTitle(exercise);

if (exercise.course) {
const course = exercise.course;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -488,12 +488,8 @@ export class ExerciseService {
}

public sendExerciseTitleToTitleService(exercise?: Exercise) {
// we only want to show the exercise group name as exercise name to the student for exam exercises.
// for tutors and more privileged users, we want to show the exercise title
if (exercise?.exerciseGroup && !exercise?.isAtLeastTutor) {
this.entityTitleService.setTitle(EntityType.EXERCISE, [exercise?.id], exercise?.exerciseGroup.title);
} else {
this.entityTitleService.setTitle(EntityType.EXERCISE, [exercise?.id], exercise?.title);
if (exercise) {
this.entityTitleService.setExerciseTitle(exercise);
}
if (exercise?.course) {
this.entityTitleService.setTitle(EntityType.COURSE, [exercise.course.id], exercise.course.title);
Expand Down
11 changes: 11 additions & 0 deletions src/main/webapp/app/shared/layouts/navbar/entity-title.service.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { HttpClient, HttpResponse } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { captureException } from '@sentry/angular';
import { Exercise } from 'app/entities/exercise.model';
import { EMPTY, Observable, ReplaySubject, Subject } from 'rxjs';

export enum EntityType {
Expand Down Expand Up @@ -88,6 +89,16 @@ export class EntityTitleService {
}
}

public setExerciseTitle(exercise: Exercise) {
// we only want to show the exercise group name as exercise name to the students for exam exercises.
// for tutors and more privileged users, we want to show the exercise title
if (exercise.exerciseGroup && !exercise?.isAtLeastTutor) {
this.setTitle(EntityType.EXERCISE, [exercise.id], exercise.exerciseGroup.title);
} else {
this.setTitle(EntityType.EXERCISE, [exercise.id], exercise.title);
}
}

/**
* Fetches the title of the given entity from the server.
*
Expand Down
31 changes: 31 additions & 0 deletions src/test/javascript/spec/service/entity-title.service.spec.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { Exercise } from 'app/entities/exercise.model';
import { EntityTitleService, EntityType } from 'app/shared/layouts/navbar/entity-title.service';
import { TestBed, fakeAsync, tick } from '@angular/core/testing';
import { MockHttpService } from '../helpers/mocks/service/mock-http.service';
Expand Down Expand Up @@ -115,4 +116,34 @@ describe('EntityTitleService', () => {
service.setTitle(type, ids, title);
expect(captureSpy).toHaveBeenCalledOnce();
});

it('sets the exercise group title for students during an exam', () => {
const exercise = { id: 1, exerciseGroup: { title: 'Group Title' }, isAtLeastTutor: false } as Exercise;
service.setExerciseTitle(exercise);

let result: string | undefined = undefined;
service.getTitle(EntityType.EXERCISE, [1]).subscribe((title) => (result = title));

expect(result).toBe('Group Title');
});

it('sets the exercise title for tutors and more privileged users', () => {
const exercise = { id: 1, exerciseGroup: { title: 'Group Title' }, isAtLeastTutor: true, title: 'Exercise Title' } as Exercise;
service.setExerciseTitle(exercise);

let result: string | undefined = undefined;
service.getTitle(EntityType.EXERCISE, [1]).subscribe((title) => (result = title));

expect(result).toBe('Exercise Title');
});

it('sets the exercise title for course exercises', () => {
const exercise = { id: 1, isAtLeastTutor: false, title: 'Exercise Title' } as Exercise;
service.setExerciseTitle(exercise);

let result: string | undefined = undefined;
service.getTitle(EntityType.EXERCISE, [1]).subscribe((title) => (result = title));

expect(result).toBe('Exercise Title');
});
});
25 changes: 3 additions & 22 deletions src/test/javascript/spec/service/exercise.service.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import { SafeHtml } from '@angular/platform-browser';
import { ExerciseCategory } from 'app/entities/exercise-category.model';
import { Observable } from 'rxjs';
import { AccountService } from 'app/core/auth/account.service';
import { EntityTitleService, EntityType } from 'app/shared/layouts/navbar/entity-title.service';
import { EntityTitleService } from 'app/shared/layouts/navbar/entity-title.service';
import { ProfileService } from 'app/shared/layouts/profiles/profile.service';

describe('Exercise Service', () => {
Expand Down Expand Up @@ -358,7 +358,7 @@ describe('Exercise Service', () => {
const profileService = TestBed.inject(ProfileService);

const accountServiceSpy = jest.spyOn(accountService, 'setAccessRightsForExerciseAndReferencedCourse');
const entityTitleServiceSpy = jest.spyOn(entityTitleService, 'setTitle');
const entityTitleServiceSpy = jest.spyOn(entityTitleService, 'setExerciseTitle');
const profileServiceSpy = jest.spyOn(profileService, 'getProfileInfo');

const category = {
Expand Down Expand Up @@ -387,7 +387,7 @@ describe('Exercise Service', () => {
expect(accountServiceSpy).toHaveBeenCalledWith(expect.objectContaining({ id: exerciseFromServer.id }));

expect(entityTitleServiceSpy).toHaveBeenCalledOnce();
expect(entityTitleServiceSpy).toHaveBeenCalledWith(EntityType.EXERCISE, [exerciseFromServer.id], exerciseFromServer.title);
expect(entityTitleServiceSpy).toHaveBeenCalledWith(exerciseFromServer);

expect(profileServiceSpy).not.toHaveBeenCalled();
});
Expand Down Expand Up @@ -520,23 +520,4 @@ describe('Exercise Service', () => {
method: 'PUT',
});
});

it('should correctly send the exercise name to the title service', () => {
const entityTitleService = TestBed.inject(EntityTitleService);
const examExerciseForStudent = { id: 1, title: 'exercise', exerciseGroup: { id: 1, title: 'exercise group' } } as Exercise;
const examExerciseForTutor = { ...examExerciseForStudent, isAtLeastTutor: true } as Exercise;
const courseExerciseForStudent = { ...examExerciseForStudent, exerciseGroup: undefined, course: { id: 2, title: 'course' } } as Exercise;
const courseExerciseForTutor = { ...courseExerciseForStudent, isAtLeastTutor: true } as Exercise;
const entityTitleServiceSpy = jest.spyOn(entityTitleService, 'setTitle');
service.sendExerciseTitleToTitleService(examExerciseForStudent);
expect(entityTitleServiceSpy).toHaveBeenCalledWith(EntityType.EXERCISE, [1], 'exercise group');
service.sendExerciseTitleToTitleService(examExerciseForTutor);
expect(entityTitleServiceSpy).toHaveBeenCalledWith(EntityType.EXERCISE, [1], 'exercise');
service.sendExerciseTitleToTitleService(courseExerciseForStudent);
expect(entityTitleServiceSpy).toHaveBeenCalledWith(EntityType.EXERCISE, [1], 'exercise');
expect(entityTitleServiceSpy).toHaveBeenCalledWith(EntityType.COURSE, [2], 'course');
service.sendExerciseTitleToTitleService(courseExerciseForTutor);
expect(entityTitleServiceSpy).toHaveBeenCalledWith(EntityType.EXERCISE, [1], 'exercise');
expect(entityTitleServiceSpy).toHaveBeenCalledWith(EntityType.COURSE, [2], 'course');
});
});

0 comments on commit f70a3d2

Please sign in to comment.