ghostguild-org/server/api/members/my-calendar.get.js

114 lines
3 KiB
JavaScript

import Event from "../../models/event";
import Member from "../../models/member";
export default defineEventHandler(async (event) => {
const query = getQuery(event);
const { memberId } = query;
if (!memberId) {
throw createError({
statusCode: 400,
statusMessage: "Member ID is required",
});
}
try {
// Verify member exists
const member = await Member.findById(memberId);
if (!member) {
throw createError({
statusCode: 404,
statusMessage: "Member not found",
});
}
// Find all events where the user is registered
const events = await Event.find({
"registrations.memberId": memberId,
isCancelled: { $ne: true },
})
.select("title slug description startDate endDate location")
.sort({ startDate: 1 });
// Generate iCal format
const ical = generateICalendar(events, member);
// Set headers for calendar subscription (not download)
setHeader(event, "Content-Type", "text/calendar; charset=utf-8");
setHeader(event, "Cache-Control", "no-cache, no-store, must-revalidate");
setHeader(event, "Pragma", "no-cache");
setHeader(event, "Expires", "0");
return ical;
} catch (error) {
console.error("Error generating calendar:", error);
if (error.statusCode) {
throw error;
}
throw createError({
statusCode: 500,
statusMessage: "Failed to generate calendar",
});
}
});
function generateICalendar(events, member) {
const now = new Date();
const timestamp = now
.toISOString()
.replace(/[-:]/g, "")
.replace(/\.\d{3}/, "");
let ical = [
"BEGIN:VCALENDAR",
"VERSION:2.0",
"PRODID:-//Ghost Guild//Events Calendar//EN",
"CALSCALE:GREGORIAN",
"METHOD:PUBLISH",
"X-WR-CALNAME:Ghost Guild - My Events",
"X-WR-TIMEZONE:UTC",
"X-WR-CALDESC:Your registered Ghost Guild events",
"REFRESH-INTERVAL;VALUE=DURATION:PT1H",
"X-PUBLISHED-TTL:PT1H",
];
events.forEach((evt) => {
const eventStart = new Date(evt.startDate);
const eventEnd = new Date(evt.endDate);
const dtstart = eventStart
.toISOString()
.replace(/[-:]/g, "")
.replace(/\.\d{3}/, "");
const dtend = eventEnd
.toISOString()
.replace(/[-:]/g, "")
.replace(/\.\d{3}/, "");
const dtstamp = timestamp;
// Clean description for iCal format
const description = (evt.description || "")
.replace(/\n/g, "\\n")
.replace(/,/g, "\\,");
const eventUrl = `https://ghostguild.org/events/${evt.slug || evt._id}`;
ical.push("BEGIN:VEVENT");
ical.push(`UID:${evt._id}@ghostguild.org`);
ical.push(`DTSTAMP:${dtstamp}`);
ical.push(`DTSTART:${dtstart}`);
ical.push(`DTEND:${dtend}`);
ical.push(`SUMMARY:${evt.title}`);
ical.push(`DESCRIPTION:${description}\\n\\nView event: ${eventUrl}`);
ical.push(`LOCATION:${evt.location || "Online"}`);
ical.push(`URL:${eventUrl}`);
ical.push(`STATUS:CONFIRMED`);
ical.push("END:VEVENT");
});
ical.push("END:VCALENDAR");
return ical.join("\r\n");
}