Skip to content

Commit

Permalink
fix a la roster update
Browse files Browse the repository at this point in the history
  • Loading branch information
c0repwn3r committed Feb 28, 2024
1 parent c729f07 commit 41db6fd
Show file tree
Hide file tree
Showing 5 changed files with 168 additions and 60 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
-- CreateEnum
CREATE TYPE "LogType" AS ENUM ('Training', 'CertificateRevokal');

-- AlterTable
ALTER TABLE "Session" ADD COLUMN "logType" "LogType" NOT NULL DEFAULT 'Training';
6 changes: 6 additions & 0 deletions prisma/schema.prisma
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,11 @@ model Resource {
link String
}

enum LogType {
Training
CertificateRevokal
}

model Session {
id String @id
Expand All @@ -180,6 +185,7 @@ model Session {
instructor User @relation(name: "taughtSessions", fields: [instructorId], references: [id])
instructorId String
logType LogType @default(Training)
sessionType String
date DateTime
Expand Down
50 changes: 48 additions & 2 deletions src/lib/components/CertificateBadge.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,17 @@
TowerControl,
UserRound,
} from "lucide-svelte";
import * as HoverCard from "$lib/components/ui/hover-card";
import { page } from "$app/stores";
import { can } from "$lib/perms/can";
import {
REVOKE_CERTIFICATE,
REVOKE_OPENSKIES_CERTIFICATES,
REVOKE_SOLO_CERTIFICATES,
} from "$lib/perms/permissions";
import { buttonVariants } from "$lib/components/ui/button";
import * as Dialog from "$lib/components/ui/dialog";
import { Button } from "$lib/components/ui/button";
import * as HoverCard from "$lib/components/ui/hover-card";
export let cert: Certificate;
export let holder: User;
Expand All @@ -28,9 +37,18 @@
let str_name = "";
let short_name = "";
let valid_in = "";
let can_revoke = false;
$: {
parsed_position = parse_position_v2(cert.position);
if (parsed_position?.c_typ === C_TYP.Solo) {
can_revoke = can(REVOKE_SOLO_CERTIFICATES);
} else if (parsed_position?.p_typ === P_TYP.OpenSkies) {
can_revoke = can(REVOKE_OPENSKIES_CERTIFICATES);
} else {
can_revoke = can(REVOKE_CERTIFICATE);
}
color = "";
str_name = "";
short_name = "";
Expand Down Expand Up @@ -108,10 +126,13 @@
valid_in = $page.data.vacc_id;
}
}
let revokeOpen = false;
let hovercardOpen = false;
</script>

{#if parsed_position !== null && (cert.expires !== null ? cert.expires > new Date() : true)}
<HoverCard.Root>
<HoverCard.Root bind:open={hovercardOpen}>
<HoverCard.Trigger>
<Badge class={color}>
{short_name}
Expand Down Expand Up @@ -166,6 +187,31 @@
Certificate #{cert.id}
</span>
</div>
{#if can_revoke}
<Button
on:click={() => {
revokeOpen = true;
hovercardOpen = false;
}}
class="mt-2 w-full">
Revoke Certificate
</Button>
<Dialog.Root bind:open={revokeOpen}>
<Dialog.Content class="sm:max-w-[425px]">
<Dialog.Header>
<Dialog.Title>Edit profile</Dialog.Title>
<Dialog.Description>
This will immediately invalidate the certificate and add a log
to the user's training transcript that the certificate was
revoked.
</Dialog.Description>
</Dialog.Header>
<Dialog.Footer>
<Button type="submit" variant="danger">Revoke certificate</Button>
</Dialog.Footer>
</Dialog.Content>
</Dialog.Root>
{/if}
</HoverCard.Content>
</HoverCard.Root>
{/if}
157 changes: 100 additions & 57 deletions src/routes/api/cron/roster/+server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,18 @@ import { VATSIM_CORE_API_TOKEN } from "$env/static/private";
import type { RequestHandler } from "@sveltejs/kit";
import prisma from "$lib/prisma";
import { ulid } from "ulid";
import type { UserFacilityAssignment } from "@prisma/client";

interface UserRecord {
primary: UserFacilityAssignment | null;
other: UserFacilityAssignment[];
}

export const GET: RequestHandler = async () => {
console.log("[RosterUpdate] Roster update task started");

console.log("[RosterUpdate] Pulling member count from VATSIM");

let initial_vatsim_resp = await fetch(
"https://api.vatsim.net/v2/orgs/division/MENA?limit=1",
{
Expand All @@ -23,6 +31,10 @@ export const GET: RequestHandler = async () => {

let need_to_pull = initial_json.count;

console.log(
`[RosterUpdate] Loading information about ${need_to_pull} members`,
);

let real_roster_resp = await fetch(
`https://api.vatsim.net/v2/orgs/division/MENA?limit=${need_to_pull}`,
{
Expand All @@ -32,6 +44,8 @@ export const GET: RequestHandler = async () => {
},
);

console.log("[RosterUpdate] Planning");

let roster_json = await real_roster_resp.json();

if (!real_roster_resp.ok) {
Expand Down Expand Up @@ -77,6 +91,27 @@ export const GET: RequestHandler = async () => {
let askipped = 0;
let atotal = 0;

let userAssignments: string[UserFacilityAssignment] = {};

let all_assignments: UserFacilityAssignment[] =
await prisma.userFacilityAssignment.findMany();
for (let assignment of all_assignments) {
if (!userAssignments[assignment.userId]) {
userAssignments[assignment.userId] = {
primary: null,
other: [],
};
}

if (assignment.assignmentType === "Primary") {
userAssignments[assignment.userId].primary = assignment;
} else {
userAssignments[assignment.userId].other.push(assignment);
}
}

console.log("[RosterUpdate] Start updating users");

for (let roster_user of roster) {
total += 1;

Expand Down Expand Up @@ -118,7 +153,9 @@ export const GET: RequestHandler = async () => {
data: new_data,
});

console.log(`[RosterUpdate] Updated existing user ${roster_user.id}`);
console.log(
`[RosterUpdate ${total}/${roster.length}] Updated existing user ${roster_user.id}`,
);
updated += 1;
break;
}
Expand All @@ -140,36 +177,44 @@ export const GET: RequestHandler = async () => {
},
});

console.log(`[RosterUpdate] Created new user ${roster_user.id}`);
console.log(
`[RosterUpdate ${total}/${roster.length}] Created new user ${roster_user.id}`,
);
created += 1;
}

// get the user's primary assignment
let userAssignment = await prisma.userFacilityAssignment.findMany({
where: {
userId: roster_user.id.toString(),
assignmentType: "Primary",
},
});
let userRecord = userAssignments[roster_user.id.toString()];

let divisionUserAssignment = await prisma.userFacilityAssignment.findUnique(
{
where: {
userId_facilityId_assignmentType: {
userId: roster_user.id.toString(),
assignmentType: "Secondary",
facilityId: "MENA",
},
},
},
);
let needsCreateDivisional = true;
let needsVacc: "create" | "update" | "leavealone" = "leavealone";

atotal += 1;
if (!userRecord) {
needsCreateDivisional = true;
if (vacc) {
needsVacc = "create";
}
} else {
if (vacc && !userRecord.primary) {
needsVacc = "create";
} else if (vacc && userRecord.primary.facilityId !== vacc) {
needsVacc = "update";
} else {
needsVacc = "leavealone";
}

for (let otherA of userRecord.other) {
if (otherA.facilityId === "MENA") {
needsCreateDivisional = false;
}
}
}

if (!divisionUserAssignment) {
atotal += 1;
if (needsCreateDivisional) {
assigned += 1;
console.log(
`[RosterUpdate] Assigned ${roster_user.id} to MENA as a secondary divisional assignment`,
`[RosterUpdate ${total}/${roster.length}] Assigned ${roster_user.id} to MENA as a secondary divisional assignment`,
);
await prisma.userFacilityAssignment.create({
data: {
Expand All @@ -180,46 +225,44 @@ export const GET: RequestHandler = async () => {
},
});
} else {
console.log(
`[RosterUpdate ${total}/${roster.length}] Skipped assignment of ${roster_user.id} as they already have division assignment`,
);
askipped += 1;
}

if (vacc) {
atotal += 1;
if (userAssignment.length === 0) {
// create it
assigned += 1;
console.log(
`[RosterUpdate] Assigned ${roster_user.id} to ${vacc} as their primary facility`,
);
await prisma.userFacilityAssignment.create({
data: {
id: ulid(),
userId: roster_user.id.toString(),
facilityId: vacc,
assignmentType: "Primary",
},
});
} else {
if (userAssignment.facilityId != vacc) {
reassigned += 1;
console.log(
`[RosterUpdate] Reassigned ${roster_user.id} to ${vacc} as their new primary facility`,
);
await prisma.userFacilityAssignment.update({
where: {
id: userAssignment[0].id,
},
data: {
facilityId: vacc,
},
});
} else {
askipped += 1;
}
}
atotal += 1;
if (needsVacc === "create") {
assigned += 1;
console.log(
`[RosterUpdate ${total}/${roster.length}] Assigned ${roster_user.id} to ${vacc} as their primary facility`,
);
await prisma.userFacilityAssignment.create({
data: {
id: ulid(),
userId: roster_user.id.toString(),
facilityId: vacc,
assignmentType: "Primary",
},
});
} else if (needsVacc === "update") {
reassigned += 1;
console.log(
`[RosterUpdate ${total}/${roster.length}] Reassigned ${roster_user.id} to ${vacc} as their new primary facility from ${userRecord.primary.id}`,
);
await prisma.userFacilityAssignment.update({
where: {
id: userRecord.primary.id,
},
data: {
facilityId: vacc,
},
});
} else {
atotal += 1;
askipped += 1;
console.log(
`[RosterUpdate ${total}/${roster.length}] Skipped assignment of ${roster_user.id} to a vACC`,
);
}
}

Expand Down
10 changes: 9 additions & 1 deletion vite.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,19 @@ export default defineConfig({
"minimatch",
"zod",
"formsnap",
"sveltekit-superforms/client",
"jsonwebtoken",
"@prisma/client",
"marked",
"@unpic/placeholder",
"svelte-headless-table/plugins",
"tailwindcss/colors",
"nanoid/non-secure",
"dequal",
"@floating-ui/dom",
"focus-trap",
"svelte-headless-table",
"sveltekit-superforms/server",
"sveltekit-superforms/client",
],
},
});

0 comments on commit 41db6fd

Please sign in to comment.