Skip to content

Commit

Permalink
Start CPTs
Browse files Browse the repository at this point in the history
  • Loading branch information
ngoerlitz committed Nov 20, 2023
1 parent ab30028 commit 3748ac2
Show file tree
Hide file tree
Showing 13 changed files with 138 additions and 53 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ const DataModelAttributes = {
},
mentor_id: {
type: DataType.INTEGER,
allowNull: false,
allowNull: true, // Null for CPTs!
references: {
model: "users",
key: "id",
Expand Down
14 changes: 11 additions & 3 deletions src/Router.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ import EndorsementGroupAdminController from "./controllers/endorsement-group/End
import UserCourseProgressAdministrationController from "./controllers/user-course-progress/UserCourseProgressAdministrationController";
import SoloAdminController from "./controllers/solo/SoloAdminController";
import UserEndorsementAdminController from "./controllers/user/UserEndorsementAdminController";
import CPTAdminController from "./controllers/cpt/CPTAdminController";

const routerGroup = (callback: (router: Router) => void) => {
const router = Router();
Expand Down Expand Up @@ -185,7 +186,7 @@ router.use(
"/training-session",
routerGroup((r: Router) => {
r.get("/planned", TrainingSessionAdminController.getPlanned);
r.put("/training", TrainingSessionAdminController.createTrainingSession);
r.post("/training", TrainingSessionAdminController.createTrainingSession);
r.delete("/training", TrainingSessionAdminController.deleteTrainingSession);
r.get("/:uuid", TrainingSessionAdminController.getByUUID);
r.patch("/:uuid", TrainingSessionAdminController.updateByUUID);
Expand All @@ -199,6 +200,13 @@ router.use(
})
);

r.use(
"/cpt",
routerGroup((r: Router) => {
r.get("/available", CPTAdminController.getAvailable);
})
);

r.use(
"/endorsement-group",
routerGroup((r: Router) => {
Expand Down Expand Up @@ -318,10 +326,10 @@ router.use(

r.get("/course-manager", MentorGroupAdministrationController.getAllCourseManager);

r.post("/endorsement-group", MentorGroupAdministrationController.addEndorsementGroupByID)
r.post("/endorsement-group", MentorGroupAdministrationController.addEndorsementGroupByID);

r.get("/:mentor_group_id", MentorGroupAdministrationController.getByID);
r.get("/:mentor_group_id/endorsement-group", MentorGroupAdministrationController.getEndorsementGroupsByID)
r.get("/:mentor_group_id/endorsement-group", MentorGroupAdministrationController.getEndorsementGroupsByID);
})
);

Expand Down
35 changes: 35 additions & 0 deletions src/controllers/cpt/CPTAdminController.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { NextFunction, Request, Response } from "express";
import { TrainingSession } from "../../models/TrainingSession";
import { Op } from "sequelize";
import dayjs from "dayjs";

async function getAvailable(request: Request, response: Response, next: NextFunction) {
try {
let availableCPTs = await TrainingSession.findAll({
where: {
date: {
[Op.gt]: dayjs.utc().toDate(),
},
cpt_examiner_id: null,
},
include: [
TrainingSession.associations.training_type,
TrainingSession.associations.users,
TrainingSession.associations.training_station,
TrainingSession.associations.mentor,
],
});

availableCPTs = availableCPTs.filter(c => {
return c.training_type?.type == "cpt";
});

response.send(availableCPTs);
} catch (e) {
next(e);
}
}

export default {
getAvailable,
};
17 changes: 8 additions & 9 deletions src/controllers/mentor-group/MentorGroupAdminController.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import {NextFunction, Request, Response} from "express";
import { NextFunction, Request, Response } from "express";
import ValidationHelper, { ValidationOptions } from "../../utility/helper/ValidationHelper";
import { MentorGroup } from "../../models/MentorGroup";
import { UserBelongToMentorGroups } from "../../models/through/UserBelongToMentorGroups";
import { User } from "../../models/User";
import { HttpStatusCode } from "axios";
import _MentorGroupAdminValidator from "./_MentorGroupAdminValidator";
import {MentorGroupsBelongToEndorsementGroups} from "../../models/through/MentorGroupsBelongToEndorsementGroups";
import { MentorGroupsBelongToEndorsementGroups } from "../../models/through/MentorGroupsBelongToEndorsementGroups";

// Type used to create the mentor group. The request is of type Array<UserInMentorGroupT>
type UserInMentorGroupT = {
Expand Down Expand Up @@ -323,14 +323,14 @@ async function removeMember(request: Request, response: Response) {

async function getEndorsementGroupsByID(request: Request, response: Response, next: NextFunction) {
try {
const params = request.params as {mentor_group_id: string};
const params = request.params as { mentor_group_id: string };
// TODO: Validate

const mentorGroup = await MentorGroup.findOne({
where: {
id: params.mentor_group_id
id: params.mentor_group_id,
},
include: [MentorGroup.associations.endorsement_groups]
include: [MentorGroup.associations.endorsement_groups],
});

if (mentorGroup == null) {
Expand All @@ -346,16 +346,15 @@ async function getEndorsementGroupsByID(request: Request, response: Response, ne

async function addEndorsementGroupByID(request: Request, response: Response, next: NextFunction) {
try {
const body = request.body as {mentor_group_id: string; endorsement_group_id: string};
const body = request.body as { mentor_group_id: string; endorsement_group_id: string };
// TODO: Validate

await MentorGroupsBelongToEndorsementGroups.create({
mentor_group_id: Number(body.mentor_group_id),
endorsement_group_id: Number(body.endorsement_group_id)
endorsement_group_id: Number(body.endorsement_group_id),
});

response.sendStatus(HttpStatusCode.Ok);

} catch (e) {
next(e);
}
Expand All @@ -373,5 +372,5 @@ export default {
getMembers,
getAllCourseManager,
getEndorsementGroupsByID,
addEndorsementGroupByID
addEndorsementGroupByID,
};
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ async function _getOpenTrainingRequests(): Promise<TrainingRequest[]> {

/**
* Returns all training requests that the current user is able to mentor based on his mentor groups
* DOESN'T RETURN CPT REQUESTS!
* @param request
* @param response
*/
Expand All @@ -50,7 +51,7 @@ async function getOpen(request: Request, response: Response) {
}

trainingRequests = trainingRequests.filter((req: TrainingRequest) => {
return courseIDs.includes(req.course_id);
return courseIDs.includes(req.course_id) && req.training_type?.type != "cpt";
});

response.send(trainingRequests);
Expand Down
67 changes: 51 additions & 16 deletions src/controllers/training-session/TrainingSessionAdminController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,14 @@ async function createTrainingSession(request: Request, response: Response) {
// TODO: Check if the mentor of the course is even allowed to create such a session!

const requestUser: User = request.body.user as User;
const data = request.body.data as { course_uuid?: string; date?: string; training_type_id?: number; training_station_id?: number; user_ids?: number[] };
const data = request.body as {
course_uuid?: string;
cpt_beisitzer?: boolean;
date?: string;
training_type_id?: number;
training_station_id?: number;
user_ids?: number[];
};

const validation = _TrainingSessionAdminValidator.validateCreateSessionRequest(data);

Expand All @@ -46,7 +53,13 @@ async function createTrainingSession(request: Request, response: Response) {
include: [Course.associations.users],
});

if (course == null) {
const trainingType = await TrainingType.findOne({
where: {
id: data.training_type_id,
},
});

if (course == null || trainingType == null) {
response.sendStatus(HttpStatusCode.BadRequest);
return;
}
Expand All @@ -63,15 +76,28 @@ async function createTrainingSession(request: Request, response: Response) {
return;
}

// Create Session
const trainingSession = await TrainingSession.create({
uuid: generateUUID(),
mentor_id: requestUser.id,
training_station_id: data.training_station_id,
date: dayjs.utc(data.date).toDate(),
training_type_id: data.training_type_id,
course_id: course.id,
});
let trainingSession;
if (trainingType.type != "cpt" || data.cpt_beisitzer) {
// Either the training type is NOT CPT, or - if it is CPT - the user wants to be beisitzer

// Create Session
trainingSession = await TrainingSession.create({
uuid: generateUUID(),
mentor_id: requestUser.id,
training_station_id: data.training_station_id,
date: dayjs.utc(data.date).toDate(),
training_type_id: data.training_type_id,
course_id: course.id,
});
} else {
trainingSession = await TrainingSession.create({
uuid: generateUUID(),
training_station_id: data.training_station_id,
date: dayjs.utc(data.date).toDate(),
training_type_id: data.training_type_id,
course_id: course.id,
});
}

if (trainingSession == null) {
response.sendStatus(HttpStatusCode.InternalServerError);
Expand Down Expand Up @@ -134,11 +160,19 @@ async function updateByUUID(request: Request, response: Response, next: NextFunc
}

const trainingStationIDNum = Number(body.training_station_id);
await session.update({
mentor_id: Number(body.mentor_id),
date: dayjs.utc(body.date).toDate(),
training_station_id: trainingStationIDNum == -1 ? null : trainingStationIDNum,
});
if (body.mentor_id == "-1") {
await session.update({
mentor_id: null,
date: dayjs.utc(body.date).toDate(),
training_station_id: trainingStationIDNum == -1 ? null : trainingStationIDNum,
});
} else {
await session.update({
mentor_id: Number(body.mentor_id),
date: dayjs.utc(body.date).toDate(),
training_station_id: trainingStationIDNum == -1 ? null : trainingStationIDNum,
});
}

response.sendStatus(HttpStatusCode.Ok);
} catch (e) {
Expand Down Expand Up @@ -212,6 +246,7 @@ async function getByUUID(request: Request, response: Response) {
},
include: [
TrainingSession.associations.course,
TrainingSession.associations.cpt_examiner,
{
association: TrainingSession.associations.users,
through: {
Expand Down
24 changes: 13 additions & 11 deletions src/controllers/training-session/TrainingSessionController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -107,17 +107,19 @@ async function withdrawFromSessionByUUID(request: Request, response: Response) {
await session.destroy();
}

await NotificationLibrary.sendUserNotification({
user_id: session.mentor_id,
message_de: `${user.first_name} ${user.last_name} (${user.id}) hat sich von der geplanten Session (${session.training_type?.name}) am ${dayjs(
session.date
).format("DD.MM.YYYY")} abgemeldet`,
message_en: `${user.first_name} ${user.last_name} (${user.id}) withdrew from the planned session (${session.training_type?.name}) on ${dayjs(
session.date
).format("DD.MM.YYYY")}`,
severity: "danger",
icon: "door-exit",
});
if (session.mentor_id) {
await NotificationLibrary.sendUserNotification({
user_id: session.mentor_id,
message_de: `${user.first_name} ${user.last_name} (${user.id}) hat sich von der geplanten Session (${session.training_type?.name}) am ${dayjs(
session.date
).format("DD.MM.YYYY")} abgemeldet`,
message_en: `${user.first_name} ${user.last_name} (${user.id}) withdrew from the planned session (${session.training_type?.name}) on ${dayjs(
session.date
).format("DD.MM.YYYY")}`,
severity: "danger",
icon: "door-exit",
});
}

response.sendStatus(HttpStatusCode.NoContent);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,11 @@ function validateCreateSessionRequest(data: any): ValidatorType {
validationObject: data.course_uuid,
toValidate: [{ val: ValidationOptions.NON_NULL }],
},
{
name: "cpt_beisitzer",
validationObject: data.cpt_beisitzer,
toValidate: [{ val: ValidationOptions.NON_NULL }],
},
{
name: "date",
validationObject: data.date,
Expand Down
2 changes: 1 addition & 1 deletion src/models/MentorGroup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { DataType } from "sequelize-typescript";
import { sequelize } from "../core/Sequelize";
import { Course } from "./Course";
import { UserBelongToMentorGroups } from "./through/UserBelongToMentorGroups";
import {EndorsementGroup} from "./EndorsementGroup";
import { EndorsementGroup } from "./EndorsementGroup";

export class MentorGroup extends Model<InferAttributes<MentorGroup>, InferCreationAttributes<MentorGroup>> {
//
Expand Down
4 changes: 2 additions & 2 deletions src/models/TrainingSession.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,13 @@ export class TrainingSession extends Model<InferAttributes<TrainingSession>, Inf
// Attributes
//
declare uuid: string;
declare mentor_id: number;
declare course_id: number;

//
// Optional Attributes
//
declare id: CreationOptional<number>;
declare mentor_id: CreationOptional<number> | null; // NULL for CPTs without Beisitzer ONLY!
declare completed: CreationOptional<boolean>;
declare date: CreationOptional<Date> | null;
declare cpt_examiner_id: CreationOptional<number> | null;
Expand Down Expand Up @@ -72,7 +72,7 @@ TrainingSession.init(
},
mentor_id: {
type: DataType.INTEGER,
allowNull: false,
allowNull: true,
references: {
model: "users",
key: "id",
Expand Down
8 changes: 4 additions & 4 deletions src/models/associations/MentorGroupAssociations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ import { User } from "../User";
import { UserBelongToMentorGroups } from "../through/UserBelongToMentorGroups";
import { MentorGroup } from "../MentorGroup";
import Logger, { LogLevels } from "../../utility/Logger";
import {EndorsementGroup} from "../EndorsementGroup";
import {MentorGroupsBelongToEndorsementGroups} from "../through/MentorGroupsBelongToEndorsementGroups";
import { EndorsementGroup } from "../EndorsementGroup";
import { MentorGroupsBelongToEndorsementGroups } from "../through/MentorGroupsBelongToEndorsementGroups";

export function registerMentorGroupAssociations() {
User.belongsToMany(MentorGroup, {
Expand All @@ -30,14 +30,14 @@ export function registerMentorGroupAssociations() {
as: "endorsement_groups",
through: MentorGroupsBelongToEndorsementGroups,
foreignKey: "mentor_group_id",
otherKey: "endorsement_group_id"
otherKey: "endorsement_group_id",
});

EndorsementGroup.belongsToMany(MentorGroup, {
as: "mentor_groups",
through: MentorGroupsBelongToEndorsementGroups,
foreignKey: "endorsement_group_id",
otherKey: "mentor_group_id"
otherKey: "mentor_group_id",
});

Logger.log(LogLevels.LOG_INFO, "[MentorGroupAssociations]");
Expand Down
4 changes: 2 additions & 2 deletions src/models/through/EndorsementGroupsBelongsToUsers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { DataType } from "sequelize-typescript";
import { sequelize } from "../../core/Sequelize";
import { UserSolo } from "../UserSolo";
import { User } from "../User";
import {EndorsementGroup} from "../EndorsementGroup";
import { EndorsementGroup } from "../EndorsementGroup";

export class EndorsementGroupsBelongsToUsers extends Model<
InferAttributes<EndorsementGroupsBelongsToUsers>,
Expand All @@ -12,7 +12,7 @@ export class EndorsementGroupsBelongsToUsers extends Model<
//
// Attributes
//
declare endorsement_group_id: ForeignKey<EndorsementGroup['id']>;
declare endorsement_group_id: ForeignKey<EndorsementGroup["id"]>;
declare user_id: number;

//
Expand Down
Loading

0 comments on commit 3748ac2

Please sign in to comment.