Skip to content

Commit

Permalink
solos
Browse files Browse the repository at this point in the history
  • Loading branch information
ngoerlitz committed Nov 15, 2023
1 parent 9367eab commit 66ef510
Show file tree
Hide file tree
Showing 7 changed files with 134 additions and 10 deletions.
2 changes: 2 additions & 0 deletions src/Router.ts
Original file line number Diff line number Diff line change
Expand Up @@ -299,6 +299,8 @@ router.use(
routerGroup((r: Router) => {
r.post("/", SoloAdminController.createSolo);
r.patch("/", SoloAdminController.updateSolo);

r.post("/extend", SoloAdminController.extendSolo);
})
);

Expand Down
115 changes: 110 additions & 5 deletions src/controllers/solo/SoloAdminController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import dayjs from "dayjs";
import { HttpStatusCode } from "axios";
import { User } from "../../models/User";
import { EndorsementGroupsBelongsToUsers } from "../../models/through/EndorsementGroupsBelongsToUsers";
import { TrainingSession } from "../../models/TrainingSession";

type CreateSoloRequestBody = {
solo_duration: string;
Expand All @@ -15,6 +16,12 @@ type CreateSoloRequestBody = {

type UpdateSoloRequestBody = Omit<CreateSoloRequestBody, "endorsement_group_id">;

/**
* Create a new Solo
* @param request
* @param response
* @param next
*/
async function createSolo(request: Request, response: Response, next: NextFunction) {
try {
const user: User = request.body.user;
Expand Down Expand Up @@ -45,7 +52,13 @@ async function createSolo(request: Request, response: Response, next: NextFuncti
where: {
id: body.trainee_id,
},
include: [User.associations.user_solo, User.associations.endorsement_groups],
include: [
{
association: User.associations.user_solo,
include: [UserSolo.associations.solo_creator],
},
User.associations.endorsement_groups,
],
});

response.status(HttpStatusCode.Created).send(returnUser);
Expand All @@ -54,9 +67,14 @@ async function createSolo(request: Request, response: Response, next: NextFuncti
}
}

/**
* Updates the solo (potentially using the contingent)
* @param request
* @param response
* @param next
*/
async function updateSolo(request: Request, response: Response, next: NextFunction) {
try {
const user: User = request.body.user;
const body = request.body as UpdateSoloRequestBody;
_SoloAdminValidator.validateUpdateRequest(body);

Expand All @@ -72,11 +90,97 @@ async function updateSolo(request: Request, response: Response, next: NextFuncti
}

const newDuration = currentSolo.solo_used + Number(body.solo_duration);
await currentSolo.update({
solo_used: newDuration,
current_solo_end: dayjs.utc(currentSolo.current_solo_start).add(newDuration, "days").toDate(),

// If solo_start == NULL, then the solo is still active
if (body.solo_start == null) {
await currentSolo.update({
created_by: request.body.user.id,
solo_used: newDuration,
current_solo_end: dayjs.utc(currentSolo.current_solo_start).add(newDuration, "days").toDate(),
});
} else {
// If solo_start != NULL, then the solo is inactive and the new days have to be calculated (newDuration, for example, isn't correct! It's start_date + Number(body.solo_duration)
// Else we'll add the entire solo duration to the length again :).
await currentSolo.update({
created_by: request.body.user.id,
solo_used: newDuration,
current_solo_start: dayjs.utc(body.solo_start).toDate(),
current_solo_end: dayjs.utc(body.solo_start).add(Number(body.solo_duration), "days").toDate(),
});
}

response.sendStatus(HttpStatusCode.Ok);
} catch (e) {
next(e);
}
}

/**
* Validates and extends solo
* @param request
* @param response
* @param next
*/
async function extendSolo(request: Request, response: Response, next: NextFunction) {
try {
const body = request.body as { trainee_id: string };
_SoloAdminValidator.validateExtensionRequest(body);

// Check the user has had a training in the last 20 days.
const user = await User.findOne({
where: {
id: body.trainee_id,
},
include: [
{
association: User.associations.training_sessions,
include: [TrainingSession.associations.training_type],
},
],
});

if (user == null || user.training_sessions == null) {
response.sendStatus(HttpStatusCode.NotFound);
return;
}

let cpt_planned = false;
let training_last_20_days = false;
for (const trainingSession of user.training_sessions) {
if (
trainingSession.date != null &&
trainingSession.date > dayjs.utc().subtract(20, "days").startOf("day").toDate() &&
trainingSession.training_type?.type != "cpt" &&
trainingSession.TrainingSessionBelongsToUsers?.passed
) {
training_last_20_days = true;
}

if (trainingSession.training_type?.type == "cpt") {
cpt_planned = true;
}
}

if (!cpt_planned || !training_last_20_days) {
response.status(HttpStatusCode.BadRequest).send({
cpt_planned: cpt_planned,
training_last_20_days: training_last_20_days,
});
return;
}

// Here, both cases are valid, we can extend the solo no problem!
const solo = await UserSolo.findOne({
where: {
user_id: user.id,
},
});

if (solo == null) {
response.sendStatus(HttpStatusCode.InternalServerError);
return;
}

response.sendStatus(HttpStatusCode.Ok);
} catch (e) {
next(e);
Expand All @@ -86,4 +190,5 @@ async function updateSolo(request: Request, response: Response, next: NextFuncti
export default {
createSolo,
updateSolo,
extendSolo,
};
15 changes: 15 additions & 0 deletions src/controllers/solo/_SoloAdmin.validator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,22 @@ function validateUpdateRequest(data: any) {
}
}

function validateExtensionRequest(data: any) {
const validation = ValidationHelper.validate([
{
name: "trainee_id",
validationObject: data.trainee_id,
toValidate: [{ val: ValidationOptions.NON_NULL }, { val: ValidationOptions.NUMBER }],
},
]);

if (validation.invalid) {
throw new ValidationException(validation);
}
}

export default {
validateCreateRequest,
validateUpdateRequest,
validateExtensionRequest,
};
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ type DataHubStations = {
frequency: string;
abbreviation: string;
description: string;
}
};

async function syncStations(request: Request, response: Response, next: NextFunction) {
try {
Expand All @@ -57,18 +57,18 @@ async function syncStations(request: Request, response: Response, next: NextFunc
for (const station of stations) {
if (station.logon.length === 0 || station.frequency.length === 0) continue;

const dbStation = await TrainingStation.findOne({where: {callsign: station.logon}});
const dbStation = await TrainingStation.findOne({ where: { callsign: station.logon } });
if (dbStation == null) {
await TrainingStation.create({
callsign: station.logon,
frequency: Number(station.frequency)
frequency: Number(station.frequency),
});
continue;
}

await dbStation.update({
callsign: station.logon,
frequency: Number(station.frequency)
frequency: Number(station.frequency),
});
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ async function create(request: Request, response: Response) {
const trainingType = await TrainingType.create({
name: body.name,
type: body.type,
log_template_id: !isNaN(log_template_id) || log_template_id == -1 ? null : log_template_id,
log_template_id: isNaN(log_template_id) || log_template_id == -1 ? null : log_template_id,
});

response.status(HttpStatusCode.Created).send({ id: trainingType.id });
Expand Down
1 change: 1 addition & 0 deletions src/controllers/user/UserInformationAdminController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { Request, Response } from "express";
import { User } from "../../models/User";
import PermissionHelper from "../../utility/helper/PermissionHelper";
import { UserSolo } from "../../models/UserSolo";
import { EndorsementGroup } from "../../models/EndorsementGroup";

/**
* Returns the user data for a user with id request.query.user_id
Expand Down
1 change: 1 addition & 0 deletions src/models/TrainingSession.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ export class TrainingSession extends Model<InferAttributes<TrainingSession>, Inf
declare training_station?: NonAttribute<TrainingStation>;
declare course?: NonAttribute<Course>;
declare training_session_belongs_to_users?: NonAttribute<TrainingSessionBelongsToUsers[]>;
declare TrainingSessionBelongsToUsers?: NonAttribute<TrainingSessionBelongsToUsers>;

declare static associations: {
users: Association<TrainingSession, User>;
Expand Down

0 comments on commit 66ef510

Please sign in to comment.