diff --git a/db/migrations/20221115171256-create-training-request-table.ts b/db/migrations/20221115171256-create-training-request-table.ts index 4d0f84e..233c52d 100644 --- a/db/migrations/20221115171256-create-training-request-table.ts +++ b/db/migrations/20221115171256-create-training-request-table.ts @@ -1,5 +1,7 @@ import { DataType } from "sequelize-typescript"; -import { QueryInterface } from "sequelize"; +import { NonAttribute, QueryInterface, VIRTUAL } from "sequelize"; +import { TrainingRequest } from "../../src/models/TrainingRequest"; +import { TrainingStation } from "../../src/models/TrainingStation"; export const TRAINING_REQUEST_TABLE_STATUS_TYPES = ["requested", "planned", "cancelled", "completed"] as const; @@ -64,6 +66,9 @@ export const TRAINING_REQUEST_TABLE_ATTRIBUTES = { allowNull: false, defaultValue: "requested", }, + number_in_queue: { + type: DataType.VIRTUAL(DataType.INTEGER), + }, expires: { type: DataType.DATE, allowNull: false, diff --git a/src/controllers/solo/SoloAdminController.ts b/src/controllers/solo/SoloAdminController.ts index 5d69670..592eb54 100644 --- a/src/controllers/solo/SoloAdminController.ts +++ b/src/controllers/solo/SoloAdminController.ts @@ -7,7 +7,7 @@ import { User } from "../../models/User"; import { EndorsementGroupsBelongsToUsers } from "../../models/through/EndorsementGroupsBelongsToUsers"; import { TrainingSession } from "../../models/TrainingSession"; import PermissionHelper from "../../utility/helper/PermissionHelper"; -import { createSolo as vateudCreateSolo } from "../../libraries/vateud/VateudCoreLibrary"; +import { createSolo as vateudCreateSolo, removeSolo as vateudRemoveSolo } from "../../libraries/vateud/VateudCoreLibrary"; import { EndorsementGroup } from "../../models/EndorsementGroup"; type CreateSoloRequestBody = { @@ -58,7 +58,7 @@ async function createSolo(request: Request, response: Response, next: NextFuncti id: Number(body.endorsement_group_id), }, }); - + if (endorsementGroup) await vateudCreateSolo(solo, endorsementGroup); const returnUser = await User.findOne({ @@ -246,6 +246,12 @@ async function deleteSolo(request: Request, response: Response, next: NextFuncti return; } + const solo = await UserSolo.findOne({ + where: { + id: body.solo_id, + }, + }); + // 1. Delete all endorsements that are linked to the solo. await EndorsementGroupsBelongsToUsers.destroy({ where: { @@ -253,6 +259,9 @@ async function deleteSolo(request: Request, response: Response, next: NextFuncti }, }); + // 2. Delete the VATEUD Core Solo + if (solo) await vateudRemoveSolo(solo); + await UserSolo.destroy({ where: { id: body.solo_id, diff --git a/src/controllers/training-request/TrainingRequestController.ts b/src/controllers/training-request/TrainingRequestController.ts index a3290e8..6e0fe6f 100644 --- a/src/controllers/training-request/TrainingRequestController.ts +++ b/src/controllers/training-request/TrainingRequestController.ts @@ -13,7 +13,12 @@ import { HttpStatusCode } from "axios"; * @param response */ async function create(request: Request, response: Response) { - const body = request.body as { course_id: number; training_type_id: number; comment?: string; training_station_id?: number }; + const body = request.body as { + course_id: number; + training_type_id: number; + comment?: string; + training_station_id?: number; + }; const user: User = response.locals.user; // const validation = ValidationHelper.validate([ @@ -102,6 +107,10 @@ async function getOpen(request: Request, response: Response) { include: [TrainingRequest.associations.training_type, TrainingRequest.associations.course], }); + for (const trainingRequest of trainingRequests) { + await trainingRequest.appendNumberInQueue(); + } + response.send(trainingRequests); } diff --git a/src/controllers/user/UserTrainingController.ts b/src/controllers/user/UserTrainingController.ts index dbefed0..1cae916 100644 --- a/src/controllers/user/UserTrainingController.ts +++ b/src/controllers/user/UserTrainingController.ts @@ -71,6 +71,10 @@ async function getActiveRequestsByUUID(request: Request, response: Response) { include: [TrainingRequest.associations.training_type, TrainingRequest.associations.training_station], }); + for (const trainingRequest of trainingRequests) { + await trainingRequest.appendNumberInQueue(); + } + response.send( trainingRequests.filter(t => { return t.status == "requested" || t.status == "planned"; diff --git a/src/libraries/vateud/VateudCoreLibrary.ts b/src/libraries/vateud/VateudCoreLibrary.ts index 0878899..f701ef4 100644 --- a/src/libraries/vateud/VateudCoreLibrary.ts +++ b/src/libraries/vateud/VateudCoreLibrary.ts @@ -102,21 +102,23 @@ export async function createSolo(userSolo: UserSolo, endorsementGroup: Endorseme /** * Removes a solo. * On failure, it schedules a job which repeats the same request n times until it succeeds - * @param soloInfo */ -async function removeSolo(soloInfo: VateudCoreSoloRemoveT) { +export async function removeSolo(userSolo: UserSolo) { const res = await _send({ - endpoint: `/solo/${soloInfo.vateud_solo_id}`, + endpoint: `/solo/${userSolo.vateud_solo_id}`, method: "delete", }); + + if (!userSolo.vateud_solo_id) return; + if (!res) { await JobLibrary.scheduleJob(JobTypeEnum.VATEUD_CORE, { type: VateudCoreTypeEnum.SOLO_REMOVE, method: "delete", data: { solo_remove: { - local_solo_id: soloInfo.local_solo_id, - vateud_solo_id: soloInfo.vateud_solo_id, + local_solo_id: userSolo.id, + vateud_solo_id: userSolo.vateud_solo_id, }, }, }); diff --git a/src/models/TrainingRequest.ts b/src/models/TrainingRequest.ts index 80511ed..183f590 100644 --- a/src/models/TrainingRequest.ts +++ b/src/models/TrainingRequest.ts @@ -1,4 +1,4 @@ -import { Association, CreationOptional, ForeignKey, InferAttributes, InferCreationAttributes, Model, NonAttribute } from "sequelize"; +import { Association, CreationOptional, ForeignKey, InferAttributes, InferCreationAttributes, Model, NonAttribute, Op } from "sequelize"; import { User } from "./User"; import { TrainingType } from "./TrainingType"; import { TrainingSession } from "./TrainingSession"; @@ -40,6 +40,7 @@ export class TrainingRequest extends Model, Inf declare course?: NonAttribute; declare training_session?: NonAttribute; declare training_station?: NonAttribute; + declare number_in_queue?: NonAttribute; declare static associations: { user: Association; @@ -64,6 +65,16 @@ export class TrainingRequest extends Model, Inf }, }); } + + async appendNumberInQueue(): Promise { + this.number_in_queue = await TrainingRequest.count({ + where: { + training_type_id: this.training_type_id, + status: "requested", + id: { [Op.lte]: this.id }, + }, + }); + } } TrainingRequest.init(TRAINING_REQUEST_TABLE_ATTRIBUTES, {