Skip to content

Commit

Permalink
Determine correct students count for study courses #713
Browse files Browse the repository at this point in the history
  • Loading branch information
hupf committed Dec 12, 2024
1 parent 3d48667 commit 9d4dce7
Show file tree
Hide file tree
Showing 3 changed files with 101 additions and 35 deletions.
23 changes: 21 additions & 2 deletions src/app/events/services/events-state.service.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,13 @@ import * as t from "io-ts/lib/index";
import { Course } from "src/app/shared/models/course.model";
import { Event } from "src/app/shared/models/event.model";
import { StudyClass } from "src/app/shared/models/study-class.model";
import { Subscription } from "src/app/shared/models/subscription.model";
import { StorageService } from "src/app/shared/services/storage.service";
import {
buildCourse,
buildFinalGrading,
buildStudyClass,
buildSubscription,
} from "src/spec-builders";
import { buildTestModuleMetadata } from "src/spec-helpers";
import {
Expand All @@ -25,6 +27,7 @@ describe("EventsStateService", () => {
let courseEntries: EventEntry[];
let studyCourses: Event[];
let studyCoursesEntries: EventEntry[];
let subscriptions: Subscription[];
let studyClasses: StudyClass[];
let studyClassEntries: EventEntry[];
let assessments: StudyClass[];
Expand Down Expand Up @@ -197,7 +200,7 @@ describe("EventsStateService", () => {
Id: 10,
Designation: "Zentraler Gymnasialer Bildungsgang",
Leadership: "Jane Doe",
StudentCount: 42,
StudentCount: 2, // Wrong count, has to be determined via subscriptions
},
{
Id: 20,
Expand All @@ -210,11 +213,17 @@ describe("EventsStateService", () => {
{
id: 10,
designation: "Zentraler Gymnasialer Bildungsgang",
studentCount: 42,
studentCount: 3,
detailLink: "/events/students/10?returnlink=%2F",
state: null,
},
];

subscriptions = [
buildSubscription(100, 10, 1),
buildSubscription(100, 10, 2),
buildSubscription(100, 10, 3),
];
});

afterEach(() => {
Expand Down Expand Up @@ -256,6 +265,7 @@ describe("EventsStateService", () => {

expectCoursesRequest();
expectStudyCoursesRequest();
expectSubscriptionsRequest();
expectFormativeAssessmentsRequest();
expectStudyClassesRequest();

Expand Down Expand Up @@ -308,6 +318,15 @@ describe("EventsStateService", () => {
httpTestingController.expectOne(url).flush(t.array(Event).encode(response));
}

function expectSubscriptionsRequest(response = subscriptions): void {
const url =
"https://eventotest.api/Subscriptions/?filter.EventId=;10&fields=Id,EventId";

httpTestingController
.expectOne(url)
.flush(t.array(Subscription).encode(response));
}

function expectFormativeAssessmentsRequest(response = assessments): void {
const url =
"https://eventotest.api/StudyClasses/FormativeAssessments?filter.IsActive==true";
Expand Down
43 changes: 32 additions & 11 deletions src/app/events/services/events-state.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import { EventsRestService } from "src/app/shared/services/events-rest.service";
import { LoadingService } from "src/app/shared/services/loading-service";
import { StorageService } from "src/app/shared/services/storage.service";
import { StudyClassesRestService } from "src/app/shared/services/study-classes-rest.service";
import { SubscriptionsRestService } from "src/app/shared/services/subscriptions-rest.service";
import { spread } from "src/app/shared/utils/function";
import { hasRole } from "src/app/shared/utils/roles";
import { searchEntries } from "src/app/shared/utils/search";
Expand Down Expand Up @@ -97,6 +98,7 @@ export class EventsStateService {
private coursesRestService: CoursesRestService,
private eventsRestService: EventsRestService,
private studyClassRestService: StudyClassesRestService,
private subscriptionsRestService: SubscriptionsRestService,
private loadingService: LoadingService,
private storageService: StorageService,
private translate: TranslateService,
Expand Down Expand Up @@ -153,7 +155,29 @@ export class EventsStateService {
}

private loadStudyCourses(enabled: boolean): Observable<ReadonlyArray<Event>> {
return enabled ? this.eventsRestService.getStudyCourseEvents() : of([]);
if (!enabled) return of([]);

const tokenPayload = this.storageService.getPayload();
return this.eventsRestService.getStudyCourseEvents().pipe(
map((studyCourses) =>
// The user sees only the study courses he/she is leader of
studyCourses.filter((studyCourse) =>
isStudyCourseLeader(tokenPayload, studyCourse),
),
),
switchMap((studyCourses) =>
this.subscriptionsRestService
.getSubscriptionCountsByEvents(studyCourses.map((s) => s.Id))
.pipe(
map((subscriptionCounts) =>
studyCourses.map((studyCourse) => ({
...studyCourse,
StudentCount: subscriptionCounts[studyCourse.Id] ?? 0,
})),
),
),
),
);
}

private loadFormativeAssessments(
Expand Down Expand Up @@ -216,16 +240,13 @@ export class EventsStateService {
private createFromStudyCourses(
studyCourses: ReadonlyArray<Event>,
): ReadonlyArray<EventEntry> {
const tokenPayload = this.storageService.getPayload();
return studyCourses
.filter((studyCourse) => isStudyCourseLeader(tokenPayload, studyCourse)) // The user sees only the study courses he/she is leader of
.map((studyCourse) => ({
id: studyCourse.Id,
designation: studyCourse.Designation,
detailLink: this.buildStudentsLink(studyCourse.Id),
studentCount: studyCourse.StudentCount,
state: null,
}));
return studyCourses.map((studyCourse) => ({
id: studyCourse.Id,
designation: studyCourse.Designation,
detailLink: this.buildStudentsLink(studyCourse.Id),
studentCount: studyCourse.StudentCount,
state: null,
}));
}

private createFromAssessments(
Expand Down
70 changes: 48 additions & 22 deletions src/app/shared/services/subscriptions-rest.service.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { HttpClient } from "@angular/common/http";
import { Inject, Injectable } from "@angular/core";
import * as t from "io-ts";
import { Observable } from "rxjs";
import { map, switchMap } from "rxjs/operators";
import { SETTINGS, Settings } from "../../settings";
Expand All @@ -20,33 +21,58 @@ export class SubscriptionsRestService extends RestService<typeof Subscription> {
personId: number,
eventIds: number[],
): Observable<ReadonlyArray<number>> {
return this.getList({
params: {
"filter.PersonId": `=${personId}`,
"filter.EventId": `;${eventIds}`,
},
}).pipe(
switchMap(decodeArray(Identifiable)),
map((result) => result.map((i) => i.Id)),
);
return this.http
.get<unknown>(`${this.baseUrl}/`, {
params: {
"filter.PersonId": `=${personId}`,
"filter.EventId": `;${eventIds}`,
},
})
.pipe(
switchMap(decodeArray(Identifiable)),
map((result) => result.map((i) => i.Id)),
);
}

getSubscriptionCountsByEvents(
eventIds: ReadonlyArray<number>,
): Observable<Dict<number>> {
return this.http
.get<unknown>(`${this.baseUrl}/`, {
params: {
"filter.EventId": `;${eventIds.join(";")}`,
fields: ["Id", "EventId"].join(","),
},
})
.pipe(
switchMap(decodeArray(t.type({ Id: t.number, EventId: t.number }))),
map((subscriptions) =>
subscriptions.reduce<Dict<number>>((acc, s) => {
acc[s.EventId] = acc[s.EventId] ? acc[s.EventId] + 1 : 1;
return acc;
}, {}),
),
);
}

getSubscriptionsByCourse(
eventId: number,
additionalParams?: Dict<string>,
): Observable<ReadonlyArray<Subscription>> {
return this.getList({
params: {
"filter.EventId": `=${eventId}`,
...additionalParams,
fields: [
"Id",
"EventId",
"EventDesignation",
"PersonId",
"Status",
].join(","),
},
}).pipe(switchMap(decodeArray(Subscription)));
return this.http
.get<unknown>(`${this.baseUrl}/`, {
params: {
"filter.EventId": `=${eventId}`,
...additionalParams,
fields: [
"Id",
"EventId",
"EventDesignation",
"PersonId",
"Status",
].join(","),
},
})
.pipe(switchMap(decodeArray(Subscription)));
}
}

0 comments on commit 9d4dce7

Please sign in to comment.