diff --git a/handlers/api-get/milestoneICS.js b/handlers/api-get/milestoneICS.js
index 08ac4356..293405d1 100644
--- a/handlers/api-get/milestoneICS.js
+++ b/handlers/api-get/milestoneICS.js
@@ -2,17 +2,151 @@ 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 calendarCompany = "cityssm.github.io";
+const calendarProduct = configFunctions.getProperty("application.applicationName");
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://" +
+function getUrlRoot(request) {
+ return ("http://" +
request.hostname +
(configFunctions.getProperty("application.httpPort") === 80
? ""
: ":" + configFunctions.getProperty("application.httpPort")) +
- configFunctions.getProperty("reverseProxy.urlPrefix");
+ configFunctions.getProperty("reverseProxy.urlPrefix"));
+}
+function getWorkOrderUrl(request, milestone) {
+ return getUrlRoot(request) + "/workOrders/" + milestone.workOrderId;
+}
+function buildEventSummary(milestone) {
+ 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);
+ }
+ }
+ return summary;
+}
+function buildEventDescriptionHTML(request, milestone) {
+ const urlRoot = getUrlRoot(request);
+ const workOrderUrl = getWorkOrderUrl(request, milestone);
+ 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")) +
+ "
" +
+ '' +
+ ("| " + escapeHTML(configFunctions.getProperty("aliases.occupancy")) + " Type | ") +
+ ("" + escapeHTML(configFunctions.getProperty("aliases.lot")) + " | ") +
+ "Start Date | " +
+ "End Date | " +
+ ("" + escapeHTML(configFunctions.getProperty("aliases.occupants")) + " | ") +
+ "
" +
+ "";
+ for (const occupancy of milestone.workOrderLotOccupancies) {
+ descriptionHTML +=
+ "" +
+ ("| " +
+ '' +
+ 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 += " | " + "
";
+ }
+ descriptionHTML += "
";
+ }
+ if (milestone.workOrderLots.length > 0) {
+ descriptionHTML +=
+ "Related " +
+ escapeHTML(configFunctions.getProperty("aliases.lots")) +
+ "
" +
+ '' +
+ ("| " + escapeHTML(configFunctions.getProperty("aliases.lot")) + " Type | ") +
+ ("" + escapeHTML(configFunctions.getProperty("aliases.map")) + " | ") +
+ ("" + escapeHTML(configFunctions.getProperty("aliases.lot")) + " Type" + " | ") +
+ "Status | " +
+ "
" +
+ "";
+ for (const lot of milestone.workOrderLots) {
+ descriptionHTML +=
+ "" +
+ ("| " +
+ '' +
+ escapeHTML(lot.lotName) +
+ " | ") +
+ ("" + escapeHTML(lot.mapName) + " | ") +
+ ("" + escapeHTML(lot.lotType) + " | ") +
+ ("" + escapeHTML(lot.lotStatus) + " | ") +
+ "
";
+ }
+ descriptionHTML += "
";
+ }
+ 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) +
+ "
";
+ }
+ }
+ }
+ return descriptionHTML;
+}
+export const handler = (request, response) => {
+ const urlRoot = getUrlRoot(request);
const workOrderMilestoneFilters = {
workOrderTypeIds: request.query.workOrderTypeIds,
workOrderMilestoneTypeIds: request.query.workOrderMilestoneTypeIds
@@ -36,8 +170,8 @@ export const handler = (request, response) => {
calendar.url(urlRoot + "/workOrders/" + workOrderMilestones[0].workOrderId);
}
calendar.prodId({
- company: "cityssm.github.io",
- product: configFunctions.getProperty("application.applicationName")
+ company: calendarCompany,
+ product: calendarProduct
});
for (const milestone of workOrderMilestones) {
const milestoneTimePieces = (milestone.workOrderMilestoneDateString +
@@ -46,28 +180,8 @@ export const handler = (request, response) => {
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 summary = buildEventSummary(milestone);
+ const workOrderUrl = getWorkOrderUrl(request, milestone);
const eventData = {
start: milestoneDate,
created: new Date(milestone.recordCreate_timeMillis),
@@ -75,118 +189,15 @@ export const handler = (request, response) => {
lastModified: new Date(Math.max(milestone.recordUpdate_timeMillis, milestone.workOrderRecordUpdate_timeMillis)),
allDay: !milestone.workOrderMilestoneTime,
summary,
- url: workOrderURL
+ 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")) +
- "
" +
- '' +
- ("| " +
- escapeHTML(configFunctions.getProperty("aliases.occupancy")) +
- " Type | ") +
- ("" + escapeHTML(configFunctions.getProperty("aliases.lot")) + " | ") +
- "Start Date | " +
- "End Date | " +
- ("" + escapeHTML(configFunctions.getProperty("aliases.occupants")) + " | ") +
- "
" +
- "";
- for (const occupancy of milestone.workOrderLotOccupancies) {
- descriptionHTML +=
- "" +
- ("| " +
- '' +
- 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 += " | " + "
";
- }
- descriptionHTML += "
";
- }
- if (milestone.workOrderLots.length > 0) {
- descriptionHTML +=
- "Related " +
- escapeHTML(configFunctions.getProperty("aliases.lots")) +
- "
" +
- '' +
- ("| " + escapeHTML(configFunctions.getProperty("aliases.lot")) + " Type | ") +
- ("" + escapeHTML(configFunctions.getProperty("aliases.map")) + " | ") +
- ("" +
- escapeHTML(configFunctions.getProperty("aliases.lot")) +
- " Type" +
- " | ") +
- "Status | " +
- "
" +
- "";
- for (const lot of milestone.workOrderLots) {
- descriptionHTML +=
- "" +
- ("| " +
- '' +
- escapeHTML(lot.lotName) +
- " | ") +
- ("" + escapeHTML(lot.mapName) + " | ") +
- ("" + escapeHTML(lot.lotType) + " | ") +
- ("" + escapeHTML(lot.lotStatus) + " | ") +
- "
";
- }
- descriptionHTML += "
";
- }
- 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) +
- "
";
- }
- }
- }
+ const descriptionHTML = buildEventDescriptionHTML(request, milestone);
calendarEvent.description({
- plain: workOrderURL,
+ plain: workOrderUrl,
html: descriptionHTML
});
if (milestone.workOrderMilestoneCompletionDate) {
diff --git a/handlers/api-get/milestoneICS.ts b/handlers/api-get/milestoneICS.ts
index 539deb05..b4026167 100644
--- a/handlers/api-get/milestoneICS.ts
+++ b/handlers/api-get/milestoneICS.ts
@@ -7,25 +7,193 @@ import {
WorkOrderMilestoneFilters
} from "../../helpers/lotOccupancyDB/getWorkOrderMilestones.js";
-import type { RequestHandler } from "express";
+import type { RequestHandler, Request } from "express";
import * as configFunctions from "../../helpers/functions.config.js";
import { getPrintConfig } from "../../helpers/functions.print.js";
+import type * as recordTypes from "../../types/recordTypes";
+
+const calendarCompany = "cityssm.github.io";
+const calendarProduct = configFunctions.getProperty("application.applicationName");
+
const timeStringSplitRegex = /[ :-]/;
function escapeHTML(stringToEscape: string) {
return stringToEscape.replace(/[^\d A-Za-z]/g, (c) => "" + c.codePointAt(0) + ";");
}
-export const handler: RequestHandler = (request, response) => {
- const urlRoot =
+function getUrlRoot(request: Request): string {
+ return (
"http://" +
request.hostname +
(configFunctions.getProperty("application.httpPort") === 80
? ""
: ":" + configFunctions.getProperty("application.httpPort")) +
- configFunctions.getProperty("reverseProxy.urlPrefix");
+ configFunctions.getProperty("reverseProxy.urlPrefix")
+ );
+}
+
+function getWorkOrderUrl(request: Request, milestone: recordTypes.WorkOrderMilestone) {
+ return getUrlRoot(request) + "/workOrders/" + milestone.workOrderId;
+}
+
+function buildEventSummary(milestone: recordTypes.WorkOrderMilestone): string {
+ 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);
+ }
+ }
+
+ return summary;
+}
+
+function buildEventDescriptionHTML(
+ request: Request,
+ milestone: recordTypes.WorkOrderMilestone
+): string {
+ const urlRoot = getUrlRoot(request);
+ const workOrderUrl = getWorkOrderUrl(request, milestone);
+
+ 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")) +
+ "
" +
+ '' +
+ ("| " + escapeHTML(configFunctions.getProperty("aliases.occupancy")) + " Type | ") +
+ ("" + escapeHTML(configFunctions.getProperty("aliases.lot")) + " | ") +
+ "Start Date | " +
+ "End Date | " +
+ ("" + escapeHTML(configFunctions.getProperty("aliases.occupants")) + " | ") +
+ "
" +
+ "";
+
+ for (const occupancy of milestone.workOrderLotOccupancies) {
+ descriptionHTML +=
+ "" +
+ ("| " +
+ '' +
+ 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 += " | " + "
";
+ }
+
+ descriptionHTML += "
";
+ }
+
+ if (milestone.workOrderLots.length > 0) {
+ descriptionHTML +=
+ "Related " +
+ escapeHTML(configFunctions.getProperty("aliases.lots")) +
+ "
" +
+ '' +
+ ("| " + escapeHTML(configFunctions.getProperty("aliases.lot")) + " Type | ") +
+ ("" + escapeHTML(configFunctions.getProperty("aliases.map")) + " | ") +
+ ("" + escapeHTML(configFunctions.getProperty("aliases.lot")) + " Type" + " | ") +
+ "Status | " +
+ "
" +
+ "";
+
+ for (const lot of milestone.workOrderLots) {
+ descriptionHTML +=
+ "" +
+ ("| " +
+ '' +
+ escapeHTML(lot.lotName) +
+ " | ") +
+ ("" + escapeHTML(lot.mapName) + " | ") +
+ ("" + escapeHTML(lot.lotType) + " | ") +
+ ("" + escapeHTML(lot.lotStatus) + " | ") +
+ "
";
+ }
+
+ descriptionHTML += "
";
+ }
+
+ 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) +
+ "
";
+ }
+ }
+ }
+
+ return descriptionHTML;
+}
+
+export const handler: RequestHandler = (request, response) => {
+ const urlRoot = getUrlRoot(request);
/*
* Get work order milestones
@@ -62,8 +230,8 @@ export const handler: RequestHandler = (request, response) => {
}
calendar.prodId({
- company: "cityssm.github.io",
- product: configFunctions.getProperty("application.applicationName")
+ company: calendarCompany,
+ product: calendarProduct
});
/*
@@ -90,38 +258,11 @@ export const handler: RequestHandler = (request, response) => {
// Build summary (title in Outlook)
- 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 summary = buildEventSummary(milestone);
// Build URL
- const workOrderURL = urlRoot + "/workOrders/" + milestone.workOrderId;
+ const workOrderUrl = getWorkOrderUrl(request, milestone);
// Create event
@@ -137,7 +278,7 @@ export const handler: RequestHandler = (request, response) => {
),
allDay: !milestone.workOrderMilestoneTime,
summary,
- url: workOrderURL
+ url: workOrderUrl
};
if (!eventData.allDay) {
@@ -148,126 +289,10 @@ export const handler: RequestHandler = (request, response) => {
// Build description
- 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")) +
- "
" +
- '' +
- ("| " +
- escapeHTML(configFunctions.getProperty("aliases.occupancy")) +
- " Type | ") +
- ("" + escapeHTML(configFunctions.getProperty("aliases.lot")) + " | ") +
- "Start Date | " +
- "End Date | " +
- ("" + escapeHTML(configFunctions.getProperty("aliases.occupants")) + " | ") +
- "
" +
- "";
-
- for (const occupancy of milestone.workOrderLotOccupancies) {
- descriptionHTML +=
- "" +
- ("| " +
- '' +
- 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 += " | " + "
";
- }
-
- descriptionHTML += "
";
- }
-
- if (milestone.workOrderLots.length > 0) {
- descriptionHTML +=
- "Related " +
- escapeHTML(configFunctions.getProperty("aliases.lots")) +
- "
" +
- '' +
- ("| " + escapeHTML(configFunctions.getProperty("aliases.lot")) + " Type | ") +
- ("" + escapeHTML(configFunctions.getProperty("aliases.map")) + " | ") +
- ("" +
- escapeHTML(configFunctions.getProperty("aliases.lot")) +
- " Type" +
- " | ") +
- "Status | " +
- "
" +
- "";
-
- for (const lot of milestone.workOrderLots) {
- descriptionHTML +=
- "" +
- ("| " +
- '' +
- escapeHTML(lot.lotName) +
- " | ") +
- ("" + escapeHTML(lot.mapName) + " | ") +
- ("" + escapeHTML(lot.lotType) + " | ") +
- ("" + escapeHTML(lot.lotStatus) + " | ") +
- "
";
- }
-
- descriptionHTML += "
";
- }
-
- 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) +
- "
";
- }
- }
- }
+ const descriptionHTML = buildEventDescriptionHTML(request, milestone);
calendarEvent.description({
- plain: workOrderURL,
+ plain: workOrderUrl,
html: descriptionHTML
});