From c0a3b5c80c9ddb0dce07016a0fd8319f6c59d308 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nikolas=20G=C3=B6rlitz?= Date: Fri, 12 Apr 2024 22:33:08 +0200 Subject: [PATCH] add description to training type - some general clean up - add optional field to training type (description) --- .prettierignore | 2 ++ ...21115171246-create-training-types-table.ts | 4 ++++ backend/src/Application.ts | 5 +++-- .../TrainingTypeAdminController.ts | 19 +++++++---------- .../training-type/TrainingTypeController.ts | 13 +++++------- ...rCourseProgressAdministrationController.ts | 20 +++++++++++++++++- backend/src/core/Config.ts | 2 +- .../src/libraries/vatsim/ConnectLibrary.ts | 2 +- backend/src/models/TrainingType.ts | 13 ++++++++++++ .../view/_types/CVCourseUsersList.types.tsx | 10 ++++----- .../create/TrainingTypeCreate.view.tsx | 11 ++++++++++ .../view/_subpages/TTVSettings.subpage.tsx | 17 +++++++++++++-- .../_modals/CAVRequestTraining.modal.tsx | 21 ++++++++++++++----- .../_types/CAVTrainingRequestList.types.tsx | 7 +++++-- .../course/course-view/Course.view.tsx | 2 -- .../TrainingOpenRequestList.view.tsx | 3 +-- .../_types/TORLList.types.tsx | 9 +++++--- .../TrainingOpenRequestView.view.tsx | 5 +---- frontend/src/pages/login/Login.view.tsx | 3 ++- .../src/pages/login/LoginCallbackView.tsx | 6 ++++++ .../login/_partials/LoginStatus.partial.tsx | 19 +++++++++++++---- 21 files changed, 139 insertions(+), 54 deletions(-) diff --git a/.prettierignore b/.prettierignore index 9ab49a0..c7c48a9 100644 --- a/.prettierignore +++ b/.prettierignore @@ -29,6 +29,8 @@ src/**/*.js **/*.css **/*.config.ts **/*.html +**/*.d.ts +**/*.cjs index.html diff --git a/backend/db/migrations/20221115171246-create-training-types-table.ts b/backend/db/migrations/20221115171246-create-training-types-table.ts index 1ea02fe..794a28a 100644 --- a/backend/db/migrations/20221115171246-create-training-types-table.ts +++ b/backend/db/migrations/20221115171246-create-training-types-table.ts @@ -16,6 +16,10 @@ export const TRAINING_TYPES_TABLE_ATTRIBUTES = { comment: "Name of training type (eg. 'Frankfurt Tower Online'). Max length 70 chars", allowNull: false, }, + description: { + type: DataType.TEXT, + allowNull: true, + }, type: { type: DataType.ENUM(...TRAINING_TYPES_TABLE_TYPES), comment: "Type of Training Type (ie. Sim Session - Sim)", diff --git a/backend/src/Application.ts b/backend/src/Application.ts index a19dd7a..344a7a8 100644 --- a/backend/src/Application.ts +++ b/backend/src/Application.ts @@ -14,6 +14,7 @@ const application: Express = express(); function logStartupOptions() { Logger.log(LogLevels.LOG_WARN, `Debug mode: ${Config.APP_DEBUG ? "ENABLED" : "DISABLED"}`); Logger.log(LogLevels.LOG_WARN, `SQL logging: ${Config.APP_LOG_SQL ? "ENABLED" : "DISABLED"}`); + Logger.log(LogLevels.LOG_WARN, `CORS enabled: ${Config.APP_CORS_ALLOW ? "ENABLED" : "DISABLED"}`); Logger.log(LogLevels.LOG_WARN, `File Upload: {location: ${Config.FILE_STORAGE_LOCATION}, tmp: ${Config.FILE_TMP_LOCATION}}\n`); Logger.log(LogLevels.LOG_SUCCESS, `Server is running on http://${Config.APP_HOST ?? "0.0.0.0"}:${Config.APP_PORT}`, true); @@ -22,11 +23,11 @@ function logStartupOptions() { initializeApplication() .then(() => { // Basic server configuration - if (Config.APP_DEBUG) { + if (Config.APP_CORS_ALLOW) { application.use( cors({ credentials: true, - origin: Config.APP_CORS_ALLOW, + origin: "http://localhost:8000", }) ); } diff --git a/backend/src/controllers/training-type/TrainingTypeAdminController.ts b/backend/src/controllers/training-type/TrainingTypeAdminController.ts index 26f7358..f743b3b 100644 --- a/backend/src/controllers/training-type/TrainingTypeAdminController.ts +++ b/backend/src/controllers/training-type/TrainingTypeAdminController.ts @@ -20,18 +20,15 @@ async function getAll(request: Request, response: Response) { * Gets a training type by its ID * @param request * @param response + * @param next */ async function getByID(request: Request, response: Response, next: NextFunction) { try { const params = request.params as { id: string }; - // const validation = ValidationHelper.validate([ - // { - // name: "id", - // validationObject: params.id, - // toValidate: [{ val: ValidationOptions.NON_NULL }], - // }, - // ]); + Validator.validate(params, { + id: [ValidationTypeEnum.NON_NULL, ValidationTypeEnum.NUMBER], + }); const trainingType = await TrainingType.findOne({ where: { @@ -65,7 +62,7 @@ async function getByID(request: Request, response: Response, next: NextFunction) * @param response */ async function create(request: Request, response: Response) { - const body = request.body as { name: string; type: "online" | "sim" | "lesson" | "cpt"; log_template_id?: string }; + const body = request.body as { name: string; type: "online" | "sim" | "lesson" | "cpt"; log_template_id?: string; description?: string }; Validator.validate(body, { name: [ValidationTypeEnum.NON_NULL], type: [ValidationTypeEnum.NON_NULL, { option: ValidationTypeEnum.IN_ARRAY, value: ["online", "sim", "lesson", "cpt"] }], @@ -75,6 +72,7 @@ async function create(request: Request, response: Response) { const trainingType = await TrainingType.create({ name: body.name, type: body.type, + description: !body.description || body.description == "" ? null : body.description, log_template_id: isNaN(log_template_id) || log_template_id == -1 ? null : log_template_id, }); @@ -88,9 +86,7 @@ async function create(request: Request, response: Response) { */ async function update(request: Request, response: Response) { const training_type_id = request.params.id; - const body = request.body as { name: string; type: "online" | "sim" | "cpt" | "lesson"; log_template_id?: string }; - - console.log(body); + const body = request.body as { name: string; type: "online" | "sim" | "cpt" | "lesson"; log_template_id?: string; description?: string }; Validator.validate(body, { name: [ValidationTypeEnum.NON_NULL], @@ -111,6 +107,7 @@ async function update(request: Request, response: Response) { let updatedTrainingType = await trainingType.update({ name: body.name, type: body.type, + description: !body.description || body.description == "" ? null : body.description, log_template_id: body.log_template_id == null || isNaN(Number(body.log_template_id)) ? null : Number(body.log_template_id), }); diff --git a/backend/src/controllers/training-type/TrainingTypeController.ts b/backend/src/controllers/training-type/TrainingTypeController.ts index 0813e95..21bdfa4 100644 --- a/backend/src/controllers/training-type/TrainingTypeController.ts +++ b/backend/src/controllers/training-type/TrainingTypeController.ts @@ -1,23 +1,20 @@ import { NextFunction, Request, Response } from "express"; import { TrainingType } from "../../models/TrainingType"; +import Validator, { ValidationTypeEnum } from "../../utility/Validator"; async function getByID(request: Request, response: Response, next: NextFunction) { try { const params = request.params as { id: string }; - // const validation = ValidationHelper.validate([ - // { - // name: "id", - // validationObject: params.id, - // toValidate: [{ val: ValidationOptions.NON_NULL }], - // }, - // ]); + Validator.validate(params, { + id: [ValidationTypeEnum.NON_NULL, ValidationTypeEnum.NUMBER], + }); const trainingType = await TrainingType.findOne({ where: { id: params.id, }, - attributes: ["id", "name", "type"], + attributes: ["id", "name", "type", "description"], include: { association: TrainingType.associations.training_stations, attributes: ["id", "callsign", "frequency"], diff --git a/backend/src/controllers/user-course-progress/UserCourseProgressAdministrationController.ts b/backend/src/controllers/user-course-progress/UserCourseProgressAdministrationController.ts index 17a4357..994dcad 100644 --- a/backend/src/controllers/user-course-progress/UserCourseProgressAdministrationController.ts +++ b/backend/src/controllers/user-course-progress/UserCourseProgressAdministrationController.ts @@ -6,11 +6,29 @@ import { Course } from "../../models/Course"; import { TrainingRequest } from "../../models/TrainingRequest"; import { TrainingSession } from "../../models/TrainingSession"; import { UsersBelongsToCourses } from "../../models/through/UsersBelongsToCourses"; +import Validator, { ValidationTypeEnum } from "../../utility/Validator"; +/** + * Returns information about the progress of a user within the specified course. + * For example: + * - Training Requests + * - Training Sessions + * - Training Logs + * etc. + * @param request + * @param response + * @param next + */ async function getInformation(request: Request, response: Response, next: NextFunction) { try { const query = request.query as { course_uuid: string; user_id: string }; - _UserCourseProgressAdministrationValidator.validateGetAllRequest(query); + Validator.validate(query, { + course_uuid: [ValidationTypeEnum.NON_NULL], + user_id: [ValidationTypeEnum.NON_NULL, ValidationTypeEnum.NUMBER], + }); + + // TODO: Return the relevant information for this course ONLY! + // Currently, the controller returns ALL Requests and Histories for the user with this ID, not only those in the specified course! const user = await User.findOne({ where: { diff --git a/backend/src/core/Config.ts b/backend/src/core/Config.ts index f133498..175c9c9 100644 --- a/backend/src/core/Config.ts +++ b/backend/src/core/Config.ts @@ -59,7 +59,7 @@ export const Config = { // Read from .env APP_DEBUG: process.env.APP_DEBUG?.toLowerCase() == "true", APP_LOG_SQL: process.env.APP_LOG_SQL?.toLowerCase() == "true", - APP_CORS_ALLOW: process.env.APP_CORS_ALLOW ?? "*", + APP_CORS_ALLOW: process.env.APP_CORS_ALLOW == "true", APP_KEY: process.env.APP_KEY, APP_PORT: Number(process.env.APP_PORT), diff --git a/backend/src/libraries/vatsim/ConnectLibrary.ts b/backend/src/libraries/vatsim/ConnectLibrary.ts index c0c298f..3ccb9ae 100644 --- a/backend/src/libraries/vatsim/ConnectLibrary.ts +++ b/backend/src/libraries/vatsim/ConnectLibrary.ts @@ -293,7 +293,7 @@ export class VatsimConnectLibrary { */ private async _checkIsUserAllowed() { if (this.m_userData == undefined) return null; - const allowed_cids = [1373921, 1450775, 1331358, 1357290, 1439797, 1583954, 1438611, 1432304, 1439600, 1463320, 1238939]; + const allowed_cids = [1373921, 1450775, 1331358, 1357290, 1439797, 1583954, 1438611, 1432304, 1439600, 1463320, 1238939, 10000010]; if (!allowed_cids.includes(Number(this.m_userData.data.cid))) { throw new VatsimConnectException(ConnectLibraryErrors.ERR_SUSPENDED); diff --git a/backend/src/models/TrainingType.ts b/backend/src/models/TrainingType.ts index 881b7e5..f3e3700 100644 --- a/backend/src/models/TrainingType.ts +++ b/backend/src/models/TrainingType.ts @@ -10,6 +10,18 @@ import { TRAINING_TYPES_TABLE_TYPES, } from "../../db/migrations/20221115171246-create-training-types-table"; +export interface ITrainingType { + id: number; + name: string; + type: (typeof TRAINING_TYPES_TABLE_NAME)[number]; + description?: string; + log_template_id?: number; + createdAt?: Date; + updatedAt?: Date; + + training_stations?: any; +} + export class TrainingType extends Model, InferCreationAttributes> { // // Attributes @@ -21,6 +33,7 @@ export class TrainingType extends Model, InferCrea // Optional Attributes // declare id: CreationOptional; + declare description: CreationOptional | null; declare log_template_id: CreationOptional> | null; declare createdAt: CreationOptional | null; declare updatedAt: CreationOptional | null; diff --git a/frontend/src/pages/administration/lm/course/view/_types/CVCourseUsersList.types.tsx b/frontend/src/pages/administration/lm/course/view/_types/CVCourseUsersList.types.tsx index cf2e97b..bf3be6b 100644 --- a/frontend/src/pages/administration/lm/course/view/_types/CVCourseUsersList.types.tsx +++ b/frontend/src/pages/administration/lm/course/view/_types/CVCourseUsersList.types.tsx @@ -1,10 +1,10 @@ import { Link, NavigateFunction } from "react-router-dom"; import { TableColumn } from "react-data-table-component"; -import { UserModel } from "../../../../../../models/UserModel"; -import { Button } from "../../../../../../components/ui/Button/Button"; -import { COLOR_OPTS, SIZE_OPTS } from "../../../../../../assets/theme.config"; +import { UserModel } from "@/models/UserModel"; +import { Button } from "@/components/ui/Button/Button"; +import { COLOR_OPTS, SIZE_OPTS } from "@/assets/theme.config"; import { TbEye, TbTrash } from "react-icons/tb"; -import { Badge } from "../../../../../../components/ui/Badge/Badge"; +import { Badge } from "@/components/ui/Badge/Badge"; import { Dispatch } from "react"; function getColumns( @@ -25,7 +25,7 @@ function getColumns( row == null ? ( "N/A" ) : ( - + {row.first_name} {row.last_name} diff --git a/frontend/src/pages/administration/lm/training-type/create/TrainingTypeCreate.view.tsx b/frontend/src/pages/administration/lm/training-type/create/TrainingTypeCreate.view.tsx index 5891cf7..2297934 100644 --- a/frontend/src/pages/administration/lm/training-type/create/TrainingTypeCreate.view.tsx +++ b/frontend/src/pages/administration/lm/training-type/create/TrainingTypeCreate.view.tsx @@ -16,6 +16,7 @@ import useApi from "@/utils/hooks/useApi"; import { axiosInstance } from "@/utils/network/AxiosInstance"; import { AxiosResponse } from "axios"; import { TrainingTypeModel } from "@/models/TrainingTypeModel"; +import { TextArea } from "@/components/ui/Textarea/TextArea"; export function TrainingTypeCreateView() { const navigate = useNavigate(); @@ -93,6 +94,16 @@ export function TrainingTypeCreateView() { +