Skip to content

Commit

Permalink
add user notes, more profile, etc.
Browse files Browse the repository at this point in the history
  • Loading branch information
ngoerlitz committed Jun 15, 2023
1 parent 6bc07d8 commit d34d313
Show file tree
Hide file tree
Showing 14 changed files with 203 additions and 39 deletions.
1 change: 1 addition & 0 deletions .prettierignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
node_modules
dist
.github

package.json
package-lock.json
Expand Down
2 changes: 1 addition & 1 deletion db/migrations/20221115171243-create-user-session-table.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ const DataModelAttributes = {
},
client: {
type: DataType.STRING(100),
allowNull: true
allowNull: true,
},
user_id: {
type: DataType.INTEGER,
Expand Down
2 changes: 1 addition & 1 deletion src/Application.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ initializeApplication()
application.use(
cors({
credentials: true,
origin: "https://tc-dev.vatsim-germany.org",
origin: "http://localhost:8000",
})
);
application.use(cookieParser(Config.APP_KEY));
Expand Down
8 changes: 7 additions & 1 deletion src/Router.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import RoleAdministrationController from "./controllers/permission/RoleAdminCont
import UserNotificationController from "./controllers/user/UserNotificationController";
import TrainingSessionAdminController from "./controllers/training-session/TrainingSessionAdminController";
import TrainingSessionController from "./controllers/training-session/TrainingSessionController";
import UserCourseAdminController from "./controllers/user/UserCourseAdminController";

const routerGroup = (callback: (router: Router) => void) => {
const router = Router();
Expand Down Expand Up @@ -64,6 +65,7 @@ router.use(
r.get("/available", UserCourseController.getAvailableCourses);
r.get("/active", UserCourseController.getActiveCourses);
r.put("/enrol", UserCourseController.enrolInCourse);
r.delete("/withdraw", UserCourseController.withdrawFromCourseByUUID);

r.get("/info", CourseInformationController.getInformationByUUID);
r.get("/info/my", CourseInformationController.getUserCourseInformationByUUID);
Expand Down Expand Up @@ -100,7 +102,7 @@ router.use(
r.get("/:uuid", TrainingSessionController.getByUUID);
r.delete("/withdraw/:uuid", TrainingSessionController.withdrawFromSessionByUUID);
})
)
);

r.use(
"/training-type",
Expand All @@ -120,11 +122,15 @@ router.use(
r.get("/data/", UserInformationAdminController.getUserDataByID);
r.get("/data/sensitive", UserInformationAdminController.getSensitiveUserDataByID);

r.put("/note", UserNoteAdminController.createUserNote);
r.get("/notes", UserNoteAdminController.getGeneralUserNotes);
r.get("/notes/course", UserNoteAdminController.getNotesByCourseID);

r.get("/", UserController.getAll);
r.get("/min", UserController.getAllUsersMinimalData);
r.get("/sensitive", UserController.getAllSensitive);

r.get("/course/match", UserCourseAdminController.getUserCourseMatch);
})
);

Expand Down
2 changes: 1 addition & 1 deletion src/controllers/login/LoginController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ async function logout(request: Request, response: Response) {
}

async function getUserData(request: Request, response: Response) {
if (await SessionLibrary.validateSessionToken(request) == null) {
if ((await SessionLibrary.validateSessionToken(request)) == null) {
response.status(401).send({ message: "Session token invalid" });
return;
}
Expand Down
46 changes: 24 additions & 22 deletions src/controllers/training-session/TrainingSessionController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,20 +17,20 @@ async function getByUUID(request: Request, response: Response) {

const session: TrainingSession | null = await TrainingSession.findOne({
where: {
uuid: sessionUUID
uuid: sessionUUID,
},
include: [
{
association: TrainingSession.associations.users,
attributes: ["id"],
through: {attributes: []}
through: { attributes: [] },
},
TrainingSession.associations.mentor,
TrainingSession.associations.cpt_examiner,
TrainingSession.associations.training_type,
TrainingSession.associations.training_station,
TrainingSession.associations.course
]
TrainingSession.associations.course,
],
});

// Check if the user even exists in this session, else deny the request
Expand All @@ -53,13 +53,13 @@ async function withdrawFromSessionByUUID(request: Request, response: Response) {

const session: TrainingSession | null = await TrainingSession.findOne({
where: {
uuid: sessionUUID
uuid: sessionUUID,
},
include: [TrainingSession.associations.users]
include: [TrainingSession.associations.users],
});

if (session == null) {
response.status(404).send({message: "Session with this UUID not found"});
response.status(404).send({ message: "Session with this UUID not found" });
return;
}

Expand All @@ -70,8 +70,8 @@ async function withdrawFromSessionByUUID(request: Request, response: Response) {
user_id: user.id,
training_session_id: session.id,
passed: null,
log_id: null
}
log_id: null,
},
});

// Check if we can delete the entire session, or only the user
Expand All @@ -80,22 +80,24 @@ async function withdrawFromSessionByUUID(request: Request, response: Response) {
}

// Update the request to reflect this change
await TrainingRequest.update({
status: "requested",
training_session_id: null,
expires: dayjs().add(1, 'month').toDate()
}, {
where: {
user_id: user.id,
training_session_id: session.id,
await TrainingRequest.update(
{
status: "requested",
training_session_id: null,
expires: dayjs().add(1, "month").toDate(),
},
{
where: {
user_id: user.id,
training_session_id: session.id,
},
}
});
);

response.send({message: "OK"});
response.send({ message: "OK" });
}


export default {
getByUUID,
withdrawFromSessionByUUID
}
withdrawFromSessionByUUID,
};
54 changes: 54 additions & 0 deletions src/controllers/user/UserCourseAdminController.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import { Request, Response } from "express";
import { User } from "../../models/User";
import { MentorGroup } from "../../models/MentorGroup";
import { Course } from "../../models/Course";

/**
* Returns all the user's courses that the requesting user is also a mentor of
* Courses that the user is not a mentor of will be filtered out
* @param request
* @param response
*/
async function getUserCourseMatch(request: Request, response: Response) {
const reqUser: User = request.body.user;
const userID = request.query.user_id;
const mentorGroups: MentorGroup[] = await reqUser.getMentorGroupsAndCourses();

if (userID == null) {
response.status(404).send({ message: "No User ID supplied" });
return;
}

const user: User | null = await User.findOne({
where: {
id: userID.toString(),
},
include: [User.associations.courses],
});

if (user == null) {
response.status(404).send({ message: "User with this ID not found" });
return;
}

let courses: Course[] | undefined = user.courses?.filter((course: Course) => {
for (const mG of mentorGroups) {
if (mG.courses?.find((c: Course) => c.id == course.id) != null) {
return true;
}
}

return false;
});

if (courses == null) {
response.status(500).send();
return;
}

response.send(courses);
}

export default {
getUserCourseMatch,
};
33 changes: 33 additions & 0 deletions src/controllers/user/UserCourseController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { Request, Response } from "express";
import { Course } from "../../models/Course";
import { UsersBelongsToCourses } from "../../models/through/UsersBelongsToCourses";
import ValidationHelper, { ValidationOptions } from "../../utility/helper/ValidationHelper";
import { TrainingRequest } from "../../models/TrainingRequest";

/**
* Returns courses that are available to the current user (i.e. not enrolled in course)
Expand Down Expand Up @@ -120,9 +121,41 @@ async function enrolInCourse(request: Request, response: Response) {
response.send(userBelongsToCourses);
}

/**
*
* @param request
* @param response
*/
async function withdrawFromCourseByUUID(request: Request, response: Response) {
const user: User = request.body.user;
const courseID = request.body.course_id;

if (courseID == null) {
response.send(404);
return;
}

await UsersBelongsToCourses.destroy({
where: {
course_id: courseID,
user_id: user.id,
},
});

await TrainingRequest.destroy({
where: {
course_id: courseID,
user_id: user.id,
},
});

response.send({ message: "OK" });
}

export default {
getAvailableCourses,
getActiveCourses,
getMyCourses,
enrolInCourse,
withdrawFromCourseByUUID,
};
63 changes: 61 additions & 2 deletions src/controllers/user/UserNoteAdminController.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import { Request, Response } from "express";
import ValidationHelper, { ValidationOptions } from "../../utility/helper/ValidationHelper";
import { UserNote } from "../../models/UserNote";
import { User } from "../../models/User";
import { generateUUID } from "../../utility/UUID";

/**
* Gets the specified user's notes that are not linked to a course, i.e. all those, that all mentors can see
Expand All @@ -23,20 +25,77 @@ async function getGeneralUserNotes(request: Request, response: Response) {
return;
}

const notes = await UserNote.findAll({
const notes: UserNote[] = await UserNote.findAll({
where: {
user_id: user_id,
course_id: null,
},
include: {
association: UserNote.associations.user,
association: UserNote.associations.author,
attributes: ["id", "first_name", "last_name"],
},
});

response.send(notes);
}

/**
* Gets all the notes of the requested user by the specified course_id
*/
async function getNotesByCourseID(request: Request, response: Response) {
const courseID = request.query.courseID;
const userID = request.query.userID;

const notes: UserNote[] = await UserNote.findAll({
where: {
user_id: userID?.toString(),
course_id: courseID?.toString(),
},
include: {
association: UserNote.associations.author,
attributes: ["id", "first_name", "last_name"],
},
});

response.send(notes);
}

async function createUserNote(request: Request, response: Response) {
const reqUser: User = request.body.user;

const validation = ValidationHelper.validate([
{
name: "user_id",
validationObject: request.body.user_id,
toValidate: [{ val: ValidationOptions.NON_NULL }],
},
{
name: "content",
validationObject: request.body.content,
toValidate: [{ val: ValidationOptions.NON_NULL }],
},
]);

if (validation.invalid) {
response.status(400).send({ validation: validation.message, validation_failed: validation.invalid });
return;
}

const note: UserNote = await UserNote.create({
uuid: generateUUID(),
user_id: request.body.user_id,
course_id: request.body.course_id == "-1" ? null : request.body.course_id,
content: request.body.content.toString(),
author_id: reqUser.id,
});

const noteWithAuthor: UserNote | null = await note.getAuthor();

response.send(noteWithAuthor);
}

export default {
getGeneralUserNotes,
createUserNote,
getNotesByCourseID,
};
2 changes: 1 addition & 1 deletion src/exceptions/VatsimConnectException.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ export enum ConnectLibraryErrors {
ERR_AUTH_REVOKED,
ERR_INV_CODE,
ERR_NO_AUTH_RESPONSE,
ERR_AXIOS_TIMEOUT
ERR_AXIOS_TIMEOUT,
}

export class VatsimConnectException extends Error {
Expand Down
Loading

0 comments on commit d34d313

Please sign in to comment.