1
0
Fork 0
polaris-task-force/src/app/(frontend)/intelligence/missions/calendar/page.tsx
Z8MB1E 486fdca2a0 fix(missions): enforce access control on missions pages
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-09-10 16:13:51 -04:00

176 lines
5.3 KiB
TypeScript

import config from "@payload-config";
import { getPayload } from "payload";
import { headers as nextHeaders } from "next/headers";
import {
FridayCalendar,
type FridayCalendarEntry,
type FridayCalendarMission,
} from "@/components/frontend/intelligence/FridayCalendar";
import type { SideOpDialogOption } from "@/components/frontend/intelligence/CreateSideOpDialog";
import {
dateKeyOf,
nextDayKey,
parseDateKey,
wallTimeToInstant,
zonedDateKey,
} from "@/lib/intelligence/fridayTime";
export const metadata = {
title: "Friday Operations",
};
const MAX_SCHEDULED_AHEAD_MISSIONS = 2;
const FRIDAYS_SHOWN = 8;
function nextFridays(count: number): string[] {
const fridays: string[] = [];
const cursor = zonedDateKey(new Date());
const [y, m, d] = cursor.split("-").map(Number);
const utc = new Date(Date.UTC(y, m - 1, d));
while (fridays.length < count) {
if (utc.getUTCDay() === 5) {
fridays.push(dateKeyOf(utc.getUTCFullYear(), utc.getUTCMonth() + 1, utc.getUTCDate()));
}
utc.setUTCDate(utc.getUTCDate() + 1);
}
return fridays;
}
export default async function FridayCalendarPage() {
const payload = await getPayload({ config });
const { user } = await payload.auth({
headers: await nextHeaders(),
canSetHeaders: false,
});
const fridays = nextFridays(FRIDAYS_SHOWN);
const first = parseDateKey(fridays[0]);
const last = parseDateKey(nextDayKey(fridays[fridays.length - 1]));
const rangeStart = wallTimeToInstant(first.year, first.month, first.day);
const rangeEnd = wallTimeToInstant(last.year, last.month, last.day);
const missionsRes = await payload.find({
collection: "missions",
where: {
"classification.startDateTime": {
greater_than_equal: rangeStart.toISOString(),
less_than: rangeEnd.toISOString(),
},
},
sort: "classification.startDateTime",
depth: 1,
limit: 200,
user,
overrideAccess: false,
select: {
name: true,
codeName: true,
operationType: true,
ownershipAndStatus: { status: true },
classification: { startDateTime: true, map: true },
createdBy: true,
},
});
const entries: FridayCalendarEntry[] = fridays.map((fridayKey) => {
const missions: FridayCalendarMission[] = missionsRes.docs
.filter((m) => zonedDateKey(new Date(m.classification.startDateTime)) === fridayKey)
.map((m) => {
const map = m.classification.map;
const createdBy = m.createdBy;
const creator =
typeof createdBy === "object" && createdBy !== null
? (createdBy as { displayName?: string | null; username?: string | null })
: null;
return {
id: m.id,
name: m.name,
codeName: m.codeName,
status: m.ownershipAndStatus.status,
startDateTime: m.classification.startDateTime,
operationType: m.operationType,
mapName: typeof map === "object" && map !== null ? map.name : null,
hostName:
creator != null
? (creator.displayName ?? creator.username ?? null)
: null,
isOwn:
user != null &&
(typeof createdBy === "object" ? createdBy?.id : createdBy) === user.id,
};
});
const k = parseDateKey(fridayKey);
return {
fridayIso: fridayKey,
startIso: wallTimeToInstant(k.year, k.month, k.day, 20, 0).toISOString(),
missions,
};
});
let remainingSlots = 0;
let maps: SideOpDialogOption[] = [];
let campaigns: SideOpDialogOption[] = [];
let modLists: SideOpDialogOption[] = [];
if (user) {
const userId = user.id as number;
const [scheduledCount, mapsRes, campaignsRes, modListsRes] = await Promise.all([
payload.count({
collection: "missions",
where: {
and: [
{ createdBy: { equals: userId } },
{ "classification.startDateTime": { greater_than: new Date().toISOString() } },
{ "ownershipAndStatus.status": { not_in: ["Completed", "Cancelled"] } },
],
},
}),
payload.find({
collection: "maps",
overrideAccess: true,
depth: 0,
limit: 200,
sort: "name",
select: { name: true },
}),
payload.find({
collection: "campaigns",
where: { owner: { equals: userId } },
depth: 0,
limit: 100,
sort: "name",
select: { name: true },
}),
payload.find({
collection: "mod-lists",
overrideAccess: true,
depth: 0,
limit: 200,
sort: "modlistName",
select: { modlistName: true },
}),
]);
remainingSlots = Math.max(0, MAX_SCHEDULED_AHEAD_MISSIONS - scheduledCount.totalDocs);
maps = mapsRes.docs.map((m) => ({ id: m.id, name: m.name }));
campaigns = campaignsRes.docs.map((c) => ({ id: c.id, name: c.name }));
modLists = modListsRes.docs.map((l) => ({ id: l.id, name: l.modlistName }));
}
return (
<div className="p-5">
<div className="mx-auto w-full max-w-5xl">
<FridayCalendar
entries={entries}
remainingSlots={remainingSlots}
maxSlots={MAX_SCHEDULED_AHEAD_MISSIONS}
maps={maps}
campaigns={campaigns}
modLists={modLists}
/>
</div>
</div>
);
}