import ical, { ICalEventStatus } from "ical-generator"; import { getWorkOrderMilestones } from "../../helpers/lotOccupancyDB/getWorkOrderMilestones.js"; import * as configFunctions from "../../helpers/functions.config.js"; import { getPrintConfig } from "../../helpers/functions.print.js"; const timeStringSplitRegex = /[ :-]/; function escapeHTML(stringToEscape) { return stringToEscape.replace(/[^\d A-Za-z]/g, (c) => "&#" + c.codePointAt(0) + ";"); } export const handler = (request, response) => { const urlRoot = "http://" + request.hostname + (configFunctions.getProperty("application.httpPort") === 80 ? "" : ":" + configFunctions.getProperty("application.httpPort")) + configFunctions.getProperty("reverseProxy.urlPrefix"); const workOrderMilestoneFilters = { workOrderTypeIds: request.query.workOrderTypeIds, workOrderMilestoneTypeIds: request.query.workOrderMilestoneTypeIds }; if (request.query.workOrderId) { workOrderMilestoneFilters.workOrderId = request.query.workOrderId; } else { workOrderMilestoneFilters.workOrderMilestoneDateFilter = "recent"; } const workOrderMilestones = getWorkOrderMilestones(workOrderMilestoneFilters, { includeWorkOrders: true, orderBy: "date" }); const calendar = ical({ name: "Work Order Milestone Calendar", url: urlRoot + "/workOrders" }); if (request.query.workOrderId && workOrderMilestones.length > 0) { calendar.name("Work Order #" + workOrderMilestones[0].workOrderNumber); calendar.url(urlRoot + "/workOrders/" + workOrderMilestones[0].workOrderId); } calendar.prodId({ company: "cityssm.github.io", product: configFunctions.getProperty("application.applicationName") }); for (const milestone of workOrderMilestones) { const milestoneTimePieces = (milestone.workOrderMilestoneDateString + " " + milestone.workOrderMilestoneTimeString).split(timeStringSplitRegex); const milestoneDate = new Date(Number.parseInt(milestoneTimePieces[0], 10), Number.parseInt(milestoneTimePieces[1], 10) - 1, Number.parseInt(milestoneTimePieces[2], 10), Number.parseInt(milestoneTimePieces[3], 10), Number.parseInt(milestoneTimePieces[4], 10)); const milestoneEndDate = new Date(milestoneDate.getTime()); milestoneEndDate.setHours(milestoneEndDate.getHours() + 1); let summary = (milestone.workOrderMilestoneCompletionDate ? "✔ " : "") + (milestone.workOrderMilestoneTypeId ? milestone.workOrderMilestoneType : milestone.workOrderMilestoneDescription).trim(); if (milestone.workOrderLotOccupancies.length > 0) { let occupantCount = 0; for (const lotOccupancy of milestone.workOrderLotOccupancies) { for (const occupant of lotOccupancy.lotOccupancyOccupants) { occupantCount += 1; if (occupantCount === 1) { if (summary !== "") { summary += ": "; } summary += occupant.occupantName; } } } if (occupantCount > 1) { summary += " plus " + (occupantCount - 1); } } const workOrderURL = urlRoot + "/workOrders/" + milestone.workOrderId; const eventData = { start: milestoneDate, created: new Date(milestone.recordCreate_timeMillis), stamp: new Date(milestone.recordCreate_timeMillis), lastModified: new Date(Math.max(milestone.recordUpdate_timeMillis, milestone.workOrderRecordUpdate_timeMillis)), allDay: !milestone.workOrderMilestoneTime, summary, url: workOrderURL }; if (!eventData.allDay) { eventData.end = milestoneEndDate; } const calendarEvent = calendar.createEvent(eventData); let descriptionHTML = "

Milestone Description

" + "

" + escapeHTML(milestone.workOrderMilestoneDescription) + "

" + "

Work Order #" + milestone.workOrderNumber + "

" + ("

" + escapeHTML(milestone.workOrderDescription) + "

") + ("

" + workOrderURL + "

"); if (milestone.workOrderLotOccupancies.length > 0) { descriptionHTML += "

Related " + escapeHTML(configFunctions.getProperty("aliases.occupancies")) + "

" + '' + ("") + ("") + "" + "" + ("") + "" + ""; for (const occupancy of milestone.workOrderLotOccupancies) { descriptionHTML += "" + ("") + ("") + ("") + "" + "" + ""; } descriptionHTML += "
" + escapeHTML(configFunctions.getProperty("aliases.occupancy")) + " Type" + escapeHTML(configFunctions.getProperty("aliases.lot")) + "Start DateEnd Date" + escapeHTML(configFunctions.getProperty("aliases.occupants")) + "
" + '' + escapeHTML(occupancy.occupancyType) + "" + (occupancy.lotName ? escapeHTML(occupancy.lotName) : "(Not Set)") + "" + occupancy.occupancyStartDateString + "" + (occupancy.occupancyEndDate ? occupancy.occupancyEndDateString : "(No End Date)") + ""; for (const occupant of occupancy.lotOccupancyOccupants) { descriptionHTML += escapeHTML(occupant.lotOccupantType) + ": " + escapeHTML(occupant.occupantName) + "
"; } descriptionHTML += "
"; } if (milestone.workOrderLots.length > 0) { descriptionHTML += "

Related " + escapeHTML(configFunctions.getProperty("aliases.lots")) + "

" + '' + ("") + ("") + ("") + "" + "" + ""; for (const lot of milestone.workOrderLots) { descriptionHTML += "" + ("") + ("") + ("") + ("") + ""; } descriptionHTML += "
" + escapeHTML(configFunctions.getProperty("aliases.lot")) + " Type" + escapeHTML(configFunctions.getProperty("aliases.map")) + "" + escapeHTML(configFunctions.getProperty("aliases.lot")) + " Type" + "Status
" + '' + escapeHTML(lot.lotName) + "" + escapeHTML(lot.mapName) + "" + escapeHTML(lot.lotType) + "" + escapeHTML(lot.lotStatus) + "
"; } const prints = configFunctions.getProperty("settings.workOrders.prints"); if (prints.length > 0) { descriptionHTML += "

Prints

"; for (const printName of prints) { const printConfig = getPrintConfig(printName); if (printConfig) { descriptionHTML += "

" + escapeHTML(printConfig.title) + "
" + (urlRoot + "/print/" + printName + "/?workOrderId=" + milestone.workOrderId) + "

"; } } } calendarEvent.description({ plain: workOrderURL, html: descriptionHTML }); if (milestone.workOrderMilestoneCompletionDate) { calendarEvent.status(ICalEventStatus.CONFIRMED); } if (milestone.workOrderMilestoneTypeId) { calendarEvent.createCategory({ name: milestone.workOrderMilestoneType }); calendarEvent.createCategory({ name: milestone.workOrderType }); } if (milestone.workOrderMilestoneCompletionDate) { calendarEvent.createCategory({ name: "Completed" }); } if (milestone.workOrderLots.length > 0) { const lotNames = []; for (const lot of milestone.workOrderLots) { lotNames.push(lot.mapName + ": " + lot.lotName); } calendarEvent.location(lotNames.join(", ")); } if (milestone.workOrderLotOccupancies.length > 0) { let organizerSet = false; for (const lotOccupancy of milestone.workOrderLotOccupancies) { for (const occupant of lotOccupancy.lotOccupancyOccupants) { if (organizerSet) { calendarEvent.createAttendee({ name: occupant.occupantName, email: configFunctions.getProperty("settings.workOrders.calendarEmailAddress") }); } else { calendarEvent.organizer({ name: occupant.occupantName, email: configFunctions.getProperty("settings.workOrders.calendarEmailAddress") }); organizerSet = true; } } } } else { calendarEvent.organizer({ name: milestone.recordCreate_userName, email: configFunctions.getProperty("settings.workOrders.calendarEmailAddress") }); } } calendar.serve(response); }; export default handler;