Skip to content

Commit

Permalink
feat: lecturer ratings (#122)
Browse files Browse the repository at this point in the history
* feat: base for future ratings implementation, update db schema, lectureres with average ratings

* chore: delete comment
  • Loading branch information
olekszczepanowski authored Jan 5, 2025
1 parent 86aa0fa commit 9cbbe34
Show file tree
Hide file tree
Showing 18 changed files with 445 additions and 81 deletions.
89 changes: 75 additions & 14 deletions backend/app/controllers/courses_controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,42 @@ export default class CoursesController {
assert(typeof params.registration_id === "string");

const registrationId = decodeURIComponent(params.registration_id);
if (registrationId) {
return await Course.query()
.where("registrationId", registrationId)
.preload("groups");
if (!registrationId) {
return [];
}
return [];

const courses = await Course.query()
.where("registrationId", registrationId)
.preload("groups", (groupQuery) => groupQuery.preload("lecturers"));

const transformedCourses = courses.map((course) => ({
id: course.id,
name: course.name,
registrationId: course.registrationId,
createdAt: course.createdAt,
updatedAt: course.updatedAt,
groups: course.groups.map((group) => ({
id: group.id,
name: group.name,
lecturer: Array.isArray(group.lecturers)
? group.lecturers
.map((lecturer) => `${lecturer.name} ${lecturer.surname}`)
.join(", ")
: "Brak prowadzącego",
averageRating: Array.isArray(group.lecturers)
? (
group.lecturers.reduce(
(total, lecturer) =>
total + (Number.parseFloat(lecturer.averageRating) || 0),
0,
) / group.lecturers.length
).toFixed(2)
: 0,
...group.serialize(),
})),
}));

return transformedCourses;
}

/**
Expand All @@ -38,17 +68,48 @@ export default class CoursesController {
*/
async show({ params }: HttpContext) {
assert(typeof params.registration_id === "string");
assert(typeof params.id === "string");
const registrationId = decodeURIComponent(params.registration_id);
if (registrationId) {
assert(typeof params.id === "string");

return await Course.query()
.where("registrationId", registrationId)
.andWhere("id", params.id)
.preload("groups")
.firstOrFail();

if (!registrationId) {
return [];
}
return {};

const course = await Course.query()
.where("registrationId", registrationId)
.andWhere("id", params.id)
.preload("groups", (groupQuery) => groupQuery.preload("lecturers"))
.firstOrFail();

const transformedCourse = {
id: course.id,
name: course.name,
registrationId: course.registrationId,
createdAt: course.createdAt,
updatedAt: course.updatedAt,
groups: course.groups.map((group) => ({
id: group.id,
name: group.name,
lecturer: Array.isArray(group.lecturers)
? group.lecturers
.map((lecturer) => `${lecturer.name} ${lecturer.surname}`)
.join(", ")
: "Brak prowadzącego",
averageRating: Array.isArray(group.lecturers)
? (
group.lecturers.reduce(
(total, lecturer) =>
total + (Number.parseFloat(lecturer.averageRating) || 0),
0,
) / group.lecturers.length
).toFixed(2)
: 0,

...group.serialize(),
})),
};

return transformedCourse;
}

/**
Expand Down
68 changes: 58 additions & 10 deletions backend/app/controllers/groups_controller.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
import assert from "node:assert";

import type { HttpContext } from "@adonisjs/core/http";

import Group from "#models/group";
Expand All @@ -10,10 +8,36 @@ export default class GroupsController {
* Display a list of all groups in matching course
*/
async index({ params }: HttpContext) {
const courseId = params.course_id as unknown;
if (typeof courseId === "string") {
return Group.query().where("courseId", courseId);
const courseId = params.course_id as string;

if (courseId) {
const groups = await Group.query()
.where("courseId", courseId)
.preload("lecturers");

const transformedGroups = groups.map((group) => ({
id: group.id,
name: group.name,
lecturer: Array.isArray(group.lecturers)
? group.lecturers
.map((lecturer) => `${lecturer.name} ${lecturer.surname}`)
.join(", ")
: "Brak prowadzącego",
averageRating: Array.isArray(group.lecturers)
? (
group.lecturers.reduce(
(total, lecturer) =>
total + (Number.parseFloat(lecturer.averageRating) || 0),
0,
) / group.lecturers.length
).toFixed(2)
: 0,
...group.serialize(),
}));

return transformedGroups;
}

return {};
}

Expand All @@ -30,14 +54,38 @@ export default class GroupsController {
* Show individual group in matching group
*/
async show({ params }: HttpContext) {
const courseId = params.course_id as unknown;
if (typeof courseId === "string") {
assert(typeof params.id === "string");
const courseId = params.course_id as string;

return await Group.query()
if (courseId && typeof params.id === "string") {
const group = await Group.query()
.where("courseId", courseId)
.andWhere("id", params.id);
.andWhere("id", params.id)
.preload("lecturers")
.firstOrFail();

const transformedGroup = {
id: group.id,
name: group.name,
lecturer: Array.isArray(group.lecturers)
? group.lecturers
.map((lecturer) => `${lecturer.name} ${lecturer.surname}`)
.join(", ")
: "Brak prowadzącego",
averageRating: Array.isArray(group.lecturers)
? (
group.lecturers.reduce(
(total, lecturer) =>
total + (Number.parseFloat(lecturer.averageRating) || 0),
0,
) / group.lecturers.length
).toFixed(2)
: 0,
...group.serialize(),
};

return transformedGroup;
}

return {};
}

Expand Down
80 changes: 54 additions & 26 deletions backend/app/controllers/schedules_controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,27 +19,26 @@ export default class SchedulesController {
return { message: "User not authenticated." };
}

// Pobierz wszystkie harmonogramy użytkownika
const schedules = await Schedule.query()
.where("userId", userId)
.preload("registrations") // Preload registrations dla każdego harmonogramu
.preload("courses"); // Preload courses dla każdego harmonogramu
.preload("registrations")
.preload("courses");

// Przetwórz każdy harmonogram, aby uzyskać pożądaną strukturę
const transformedSchedules = await Promise.all(
schedules.map(async (schedule) => {
// Pobierz grupy powiązane z kursami w harmonogramie
const courseGroups = await schedule
.related("courses")
.query()
.preload("groups", (groupQuery) =>
groupQuery.whereExists((subQuery) =>
subQuery
.from("schedule_groups")
.whereRaw("schedule_groups.group_id = groups.id")
.andWhere("schedule_groups.schedule_id", schedule.id),
),
);
.preload("groups", (groupQuery) => {
void groupQuery
.preload("lecturers")
.whereExists((subQuery) =>
subQuery
.from("schedule_groups")
.whereRaw("schedule_groups.group_id = groups.id")
.andWhere("schedule_groups.schedule_id", schedule.id),
);
});

return {
id: schedule.id,
Expand All @@ -57,6 +56,21 @@ export default class SchedulesController {
groups: course.groups.map((group) => ({
id: group.id,
name: group.name,
lecturer: Array.isArray(group.lecturers)
? group.lecturers
.map((lecturer) => `${lecturer.name} ${lecturer.surname}`)
.join(", ")
: "Brak prowadzącego",
averageRating: Array.isArray(group.lecturers)
? (
group.lecturers.reduce(
(total, lecturer) =>
total +
(Number.parseFloat(lecturer.averageRating) || 0),
0,
) / group.lecturers.length
).toFixed(2)
: 0,
...group.serialize(),
})),
})),
Expand Down Expand Up @@ -121,24 +135,24 @@ export default class SchedulesController {
const schedule = await Schedule.query()
.where("id", scheduleId)
.andWhere("userId", userId)
.preload("registrations") // Preload registrations
.preload("courses") // Preload courses (grupy powiązane z kursami zostaną załadowane osobno)
.preload("registrations")
.preload("courses")
.firstOrFail();

// Pobranie grup powiązanych z kursami z uwzględnieniem schedule_id
const courseGroups = await schedule
.related("courses")
.query()
.preload("groups", (groupQuery) =>
groupQuery.whereExists((subQuery) =>
subQuery
.from("schedule_groups")
.whereRaw("schedule_groups.group_id = groups.id")
.andWhere("schedule_groups.schedule_id", scheduleId),
),
);

// Transformacja danych do żądanej struktury
.preload("groups", (groupQuery) => {
void groupQuery
.preload("lecturers")
.whereExists((subQuery) =>
subQuery
.from("schedule_groups")
.whereRaw("schedule_groups.group_id = groups.id")
.andWhere("schedule_groups.schedule_id", scheduleId),
);
});

const transformedSchedule = {
id: schedule.id,
userId: schedule.userId,
Expand All @@ -155,6 +169,20 @@ export default class SchedulesController {
groups: course.groups.map((group) => ({
id: group.id,
name: group.name,
lecturer: Array.isArray(group.lecturers)
? group.lecturers
.map((lecturer) => `${lecturer.name} ${lecturer.surname}`)
.join(", ")
: "Brak prowadzącego",
averageRating: Array.isArray(group.lecturers)
? (
group.lecturers.reduce(
(total, lecturer) =>
total + (Number.parseFloat(lecturer.averageRating) || 0),
0,
) / group.lecturers.length
).toFixed(2)
: 0,
...group.serialize(),
})),
})),
Expand Down
16 changes: 13 additions & 3 deletions backend/app/models/group.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
import { DateTime } from "luxon";

import { BaseModel, column } from "@adonisjs/lucid/orm";
import { BaseModel, column, manyToMany } from "@adonisjs/lucid/orm";
import type { ManyToMany } from "@adonisjs/lucid/types/relations";

import Lecturer from "./lecturer.js";

export default class Group extends BaseModel {
@column({ isPrimary: true })
Expand All @@ -18,8 +21,15 @@ export default class Group extends BaseModel {
@column()
declare group: string;

@column()
declare lecturer: string;
@manyToMany(() => Lecturer, {
localKey: "id",
pivotForeignKey: "group_id",
relatedKey: "id",
pivotRelatedForeignKey: "lecturer_id",
pivotTable: "group_lecturers",
pivotTimestamps: true,
})
declare lecturers: ManyToMany<typeof Lecturer>;

@column()
declare week: "-" | "TP" | "TN";
Expand Down
22 changes: 19 additions & 3 deletions backend/app/models/group_archive.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
import { DateTime } from "luxon";

import { BaseModel, column } from "@adonisjs/lucid/orm";
import { BaseModel, column, manyToMany } from "@adonisjs/lucid/orm";
import type { ManyToMany } from "@adonisjs/lucid/types/relations";

import Lecturer from "./lecturer.js";

export default class GroupArchive extends BaseModel {
static table = "groups_archive";
Expand All @@ -19,8 +22,15 @@ export default class GroupArchive extends BaseModel {
@column()
declare group: string;

@column()
declare lecturer: string;
@manyToMany(() => Lecturer, {
localKey: "id",
pivotForeignKey: "group_id",
relatedKey: "id",
pivotRelatedForeignKey: "lecturer_id",
pivotTable: "group_archive_lecturers",
pivotTimestamps: true,
})
declare lecturers: ManyToMany<typeof Lecturer>;

@column()
declare week: "-" | "TP" | "TN";
Expand All @@ -37,6 +47,12 @@ export default class GroupArchive extends BaseModel {
@column()
declare url: string;

@column()
declare spotsOccupied: number;

@column()
declare spotsTotal: number;

@column.dateTime({ autoCreate: true })
declare createdAt: DateTime;

Expand Down
Loading

0 comments on commit 9cbbe34

Please sign in to comment.