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

Exam mode: Show exercise group title in breadcrumbs #9254

Merged
merged 10 commits into from
Sep 9, 2024
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);
Strohgelaender marked this conversation as resolved.
Show resolved Hide resolved

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);
Strohgelaender marked this conversation as resolved.
Show resolved Hide resolved
}
if (exercise?.course) {
this.entityTitleService.setTitle(EntityType.COURSE, [exercise.course.id], exercise.course.title);
Expand Down
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);
}
}
Strohgelaender marked this conversation as resolved.
Show resolved Hide resolved

/**
* 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');
});
});
Loading