owltide/server/utils/schedule.ts

101 lines
2.7 KiB
TypeScript
Raw Normal View History

/*
SPDX-FileCopyrightText: © 2025 Hornwitser <code@hornwitser.no>
SPDX-License-Identifier: AGPL-3.0-or-later
*/
import { readSchedule, type ServerUser, writeSchedule } from '~/server/database';
import { broadcastEvent } from '~/server/streams';
import type { ApiSchedule, ApiTombstone } from '~/shared/types/api';
2025-03-07 22:28:55 +01:00
export async function updateScheduleInterestedCounts(users: ServerUser[]) {
const eventCounts = new Map<number, number>();
const eventSlotCounts = new Map<number, number>();
for (const user of users) {
if (user.deleted)
continue;
if (user.interestedEventIds)
for (const id of user.interestedEventIds)
eventCounts.set(id, (eventCounts.get(id) ?? 0) + 1);
if (user.interestedEventSlotIds)
for (const id of user.interestedEventSlotIds)
eventSlotCounts.set(id, (eventSlotCounts.get(id) ?? 0) + 1);
}
2025-03-07 22:28:55 +01:00
const schedule = await readSchedule();
if (schedule.deleted) {
throw new Error("Deleted schedule not implemented");
}
const update: ApiSchedule = {
id: schedule.id,
updatedAt: new Date().toISOString(),
events: [],
};
const updatedFrom = schedule.updatedAt;
for (const event of schedule.events ?? []) {
let modified = false;
if (event.deleted)
continue;
let count = eventCounts.get(event.id);
if (count !== event.interested) {
event.interested = eventCounts.get(event.id);
modified = true;
}
2025-03-07 22:28:55 +01:00
for (const slot of event.slots) {
let slotCount = eventSlotCounts.get(slot.id);
if (slotCount !== slot.interested) {
slot.interested = slotCount;
modified = true;
}
2025-03-07 22:28:55 +01:00
}
if (modified) {
event.updatedAt = update.updatedAt;
update.events!.push(event);
}
}
if (!update.events!.length) {
return; // No changes
2025-03-07 22:28:55 +01:00
}
schedule.updatedAt = updatedFrom;
2025-03-07 22:28:55 +01:00
await writeSchedule(schedule);
await broadcastEvent({
type: "schedule-update",
updatedFrom,
data: update,
});
}
export function canSeeAnonymous(userType: string | undefined) {
return userType === "admin";
}
export function canSeeCrew(userType: string | undefined) {
return userType === "crew" || userType === "admin";
}
/** Filters out crew visible only parts of schedule */
export function filterSchedule(schedule: ApiSchedule | ApiTombstone): ApiSchedule | ApiTombstone {
if (schedule.deleted) {
return schedule;
}
return {
id: schedule.id,
updatedAt: schedule.updatedAt,
locations: schedule.locations,
events: (schedule.events ?? [])
.map(event => (
event.deleted
? event
: event.crew
// Pretend crew events are deleted.
? { id: event.id, deleted: true, updatedAt: event.updatedAt }
: {
...event,
slots: event.slots.map(slot => ({
...slot,
assigned: undefined,
}
)),
2025-03-15 18:30:22 +01:00
})),
}
2025-03-07 22:28:55 +01:00
}