diff --git a/pages/api/endpoint/createwatchedcases_api.js b/pages/api/endpoint/createwatchedcases_api.js index 0c67b6a2..aad9fff9 100644 --- a/pages/api/endpoint/createwatchedcases_api.js +++ b/pages/api/endpoint/createwatchedcases_api.js @@ -16,38 +16,73 @@ import { getToken } from "../../../actions/core/token"; import { hashAPIPath } from "../../../actions/core/hash"; import { respondError, respondSuccess } from "../middleware/apiResponse"; import { relayGetData } from "../middleware/relayForwarding"; +import { getServerSession } from "next-auth/next"; +import { authOptions } from "../auth/[...nextauth]"; +import { azureHeaders } from "../../../actions/core/headers"; +import { escapeODataString } from "../../../actions/core/guards"; const WEBAPI_URL = process.env.RELAY_ROOT || "https://dev-pedw-ns.servicebus.windows.net/dev-pedw-hc/"; +const GUID_PATTERN = + /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i; + const recordExists = async (incidentId, contactId, accessToken) => { const filter = `$filter=pinswg_WatchedCase/incidentid eq ${incidentId} and pinswg_Contact/contactid eq ${contactId}`; - const queryUrl = `pinswg_watchlists?${filter}`; + const queryUrl = + `pinswg_watchlists?${filter}` + + "&$select=pinswg_watchlistid,_pinswg_contact_value,_pinswg_watchedcase_value,pinswg_representationsubmitted"; - try { - const response = await relayGetData({ - queryUrl, - accessToken, - requestOptionsBuilder: (token) => ({ - headers: { - Authorization: "Bearer " + token, - Accept: "application/json" - } - }) - }); + const response = await relayGetData({ + queryUrl, + accessToken, + requestOptionsBuilder: (token) => ({ + headers: { + Authorization: "Bearer " + token, + Accept: "application/json" + } + }) + }); - if (response.data.value && response.data.value.length > 0) { - return response.data.value[0]; // return the existing record - } + const records = response?.data?.value; - return null; - } catch (err) { - throw err; + if (!Array.isArray(records)) { + return { + status: "invalid", + records: [] + }; } + + return { + status: "found", + records + }; }; export default async function ApiProxy(req, res) { + if (req.method !== "POST") { + return respondError(res, { + status: 405, + code: "METHOD_NOT_ALLOWED", + message: "Only POST is supported" + }); + } + + const session = await getServerSession(req, res, authOptions(req, res)); + const authenticatedEmail = session?.user?.email; + + if ( + typeof authenticatedEmail !== "string" || + authenticatedEmail.trim().length === 0 + ) { + return respondError(res, { + status: 401, + code: "UNAUTHENTICATED", + message: "Authentication required" + }); + } + const data = req.body; const watchedCaseBind = data?.["pinswg_WatchedCase@odata.bind"]; const contactBind = data?.["pinswg_Contact@odata.bind"]; @@ -66,8 +101,13 @@ export default async function ApiProxy(req, res) { }); } - const watchedCaseMatch = watchedCaseBind.match(/\(([^)]+)\)/); - const contactMatch = contactBind.match(/\(([^)]+)\)/); + const watchedCaseMatch = watchedCaseBind.match( + /^\/incidents\(([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})\)$/i + ); + + const contactMatch = contactBind.match( + /^\/contacts\(([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})\)$/i + ); if (!watchedCaseMatch || !contactMatch) { return respondError(res, { @@ -79,26 +119,118 @@ export default async function ApiProxy(req, res) { try { const token = await getToken(); - const incidentId = watchedCaseMatch[1]; const contactId = contactMatch[1]; - const existingRecord = await recordExists( + const escapedEmail = escapeODataString(authenticatedEmail); + + const contactQueryUrl = + "contacts?$filter=emailaddress1 eq '" + + escapedEmail + + "' and statuscode eq 1&$select=contactid"; + + const contactResponse = await relayGetData({ + queryUrl: contactQueryUrl, + accessToken: token.access_token, + requestOptionsBuilder: (accessToken) => azureHeaders(accessToken) + }); + + const contacts = contactResponse?.data?.value; + + if ( + !Array.isArray(contacts) || + contacts.length !== 1 || + typeof contacts[0]?.contactid !== "string" || + !GUID_PATTERN.test(contacts[0].contactid.trim()) + ) { + return respondError(res, { + status: 403, + code: "CONTACT_IDENTITY_NOT_RESOLVED", + message: "Request not permitted" + }); + } + + if ( + contactId.trim().toLowerCase() !== + contacts[0].contactid.trim().toLowerCase() + ) { + return respondError(res, { + status: 403, + code: "CONTACT_OWNERSHIP_MISMATCH", + message: "Request not permitted" + }); + } + + const lookup = await recordExists( incidentId, contactId, token.access_token ); - let method, queryUrl; - - if (existingRecord) { - method = "patch"; - queryUrl = `pinswg_watchlists(${existingRecord.pinswg_watchlistid})`; - } else { - method = "post"; - queryUrl = "pinswg_watchlists"; + if (lookup.status === "invalid") { + return respondError(res, { + status: 500, + code: "WATCHLIST_LOOKUP_FAILED", + message: "Unable to verify existing watched-case records" + }); } + const records = lookup.records; + + const isRepresentationSubmission = + data?.pinswg_representationsubmitted != null; + + // Validate every returned record before considering it for an update. + const validRecords = records.every((record) => { + const recordID = record?.pinswg_watchlistid; + const recordContactID = record?._pinswg_contact_value; + const recordCaseID = record?._pinswg_watchedcase_value; + + return ( + typeof recordID === "string" && + GUID_PATTERN.test(recordID) && + typeof recordContactID === "string" && + GUID_PATTERN.test(recordContactID) && + typeof recordCaseID === "string" && + GUID_PATTERN.test(recordCaseID) && + recordContactID.toLowerCase() === contactId.toLowerCase() && + recordCaseID.toLowerCase() === incidentId.toLowerCase() + ); + }); + + if (!validRecords) { + return respondError(res, { + status: 403, + code: "WATCHLIST_OWNERSHIP_MISMATCH", + message: "Request not permitted" + }); + } + + const watchingOnlyRecords = records.filter( + (record) => record.pinswg_representationsubmitted == null + ); + + let existingRecord; + + if (isRepresentationSubmission) { + // Reuse a watching-only record for the first representation. + // Never overwrite an earlier representation submission. + existingRecord = + watchingOnlyRecords.length === 1 + ? watchingOnlyRecords[0] + : null; + } else { + // Watching or subscribing: prefer a watching-only record. + // Otherwise reuse an existing representation-associated record. + existingRecord = watchingOnlyRecords[0] ?? records[0] ?? null; + } + + const method = existingRecord ? "patch" : "post"; + + const queryUrl = existingRecord + ? `pinswg_watchlists(${existingRecord.pinswg_watchlistid})` + : "pinswg_watchlists"; + const config = { method: method, url: WEBAPI_URL + queryUrl + hashAPIPath(queryUrl), @@ -110,7 +242,10 @@ export default async function ApiProxy(req, res) { Authorization: "Bearer " + token.access_token, "Content-Type": "application/json" }, - data: JSON.stringify(data) + data: JSON.stringify({ + ...data, + "pinswg_Contact@odata.bind": `/contacts(${contacts[0].contactid.trim()})` + }) }; const result = await axios(config); diff --git a/tests/phase21/endpoint-handler-contract.test.cjs b/tests/phase21/endpoint-handler-contract.test.cjs index 671f6470..77eed608 100644 --- a/tests/phase21/endpoint-handler-contract.test.cjs +++ b/tests/phase21/endpoint-handler-contract.test.cjs @@ -2912,10 +2912,16 @@ test("createwatchedcases returns WATCHED_CASE_BINDINGS_REQUIRED when bindings mi getToken: async () => ({ access_token: "token" }), hashAPIPath: () => "&hash=expected", axios: async () => ({ data: {} }), - consoleLogger: () => {} + consoleLogger: () => {}, + getServerSession: async () => ({ + user: { + email: "test@example.com" + } + }), + authOptions: () => ({}) }); - const req = { body: {} }; + const req = { method: "POST", body: {} }; const res = createRes(); await mod.default(req, res); @@ -2933,10 +2939,17 @@ test("createwatchedcases returns INVALID_BINDING_FORMAT when bindings invalid", getToken: async () => ({ access_token: "token" }), hashAPIPath: () => "&hash=expected", axios: async () => ({ data: {} }), - consoleLogger: () => {} + consoleLogger: () => {}, + getServerSession: async () => ({ + user: { + email: "test@example.com" + } + }), + authOptions: () => ({}) }); const req = { + method: "POST", body: { "pinswg_WatchedCase@odata.bind": "/incidents", "pinswg_Contact@odata.bind": "/contacts" @@ -2958,13 +2971,22 @@ test("createwatchedcases catch path returns WATCHED_CASE_UPSERT_FAILED", async ( }, hashAPIPath: () => "&hash=expected", axios: async () => ({ data: {} }), - consoleLogger: () => {} + consoleLogger: () => {}, + getServerSession: async () => ({ + user: { + email: "test@example.com" + } + }), + authOptions: () => ({}) }); const req = { + method: "POST", body: { - "pinswg_WatchedCase@odata.bind": "/incidents(incident-id)", - "pinswg_Contact@odata.bind": "/contacts(contact-id)" + "pinswg_WatchedCase@odata.bind": + "/incidents(11111111-1111-1111-1111-111111111111)", + "pinswg_Contact@odata.bind": + "/contacts(22222222-2222-2222-2222-222222222222)" } }; const res = createRes(); @@ -2977,6 +2999,561 @@ test("createwatchedcases catch path returns WATCHED_CASE_UPSERT_FAILED", async ( ); }); +test("createwatchedcases rejects unauthenticated requests before CRM access", async () => { + let tokenCalls = 0; + let relayCalls = 0; + let writeCalls = 0; + + const mod = loadModule("pages/api/endpoint/createwatchedcases_api.js", { + respondError: respondErrorMock, + respondSuccess: respondSuccessMock, + getServerSession: async () => null, + authOptions: () => ({}), + getToken: async () => { + tokenCalls += 1; + return { access_token: "token" }; + }, + relayGetData: async () => { + relayCalls += 1; + return { data: { value: [] } }; + }, + hashAPIPath: () => "&hash=expected", + axios: async () => { + writeCalls += 1; + return { data: {} }; + }, + consoleLogger: () => {}, + authOptions: () => ({}) + }); + + const req = { + method: "POST", + body: { + "pinswg_WatchedCase@odata.bind": + "/incidents(11111111-1111-1111-1111-111111111111)", + "pinswg_Contact@odata.bind": + "/contacts(22222222-2222-2222-2222-222222222222)" + } + }; + + const res = createRes(); + await mod.default(req, res); + + assert.strictEqual(res.state.statusCode, 401); + assert.strictEqual(res.state.jsonBody.error.code, "UNAUTHENTICATED"); + assert.strictEqual(tokenCalls, 0); + assert.strictEqual(relayCalls, 0); + assert.strictEqual(writeCalls, 0); +}); + +test("createwatchedcases rejects another contact before CRM write", async () => { + let writeCalls = 0; + + const ownContactID = "22222222-2222-2222-2222-222222222222"; + const otherContactID = "33333333-3333-3333-3333-333333333333"; + + const mod = loadModule("pages/api/endpoint/createwatchedcases_api.js", { + respondError: respondErrorMock, + respondSuccess: respondSuccessMock, + getServerSession: async () => ({ + user: { email: "test@example.com" } + }), + authOptions: () => ({}), + getToken: async () => ({ access_token: "token" }), + azureHeaders: () => ({ + headers: { Authorization: "Bearer token" } + }), + escapeODataString: (value) => value.replace(/'/g, "''"), + relayGetData: async ({ queryUrl }) => { + if (queryUrl.startsWith("contacts?")) { + return { + data: { + value: [{ contactid: ownContactID }] + } + }; + } + + return { data: { value: [] } }; + }, + hashAPIPath: () => "&hash=expected", + axios: async () => { + writeCalls += 1; + return { data: {} }; + }, + consoleLogger: () => {} + }); + + const req = { + method: "POST", + body: { + "pinswg_WatchedCase@odata.bind": + "/incidents(11111111-1111-1111-1111-111111111111)", + "pinswg_Contact@odata.bind": `/contacts(${otherContactID})` + } + }; + + const res = createRes(); + await mod.default(req, res); + + assert.strictEqual(res.state.statusCode, 403); + assert.strictEqual( + res.state.jsonBody.error.code, + "CONTACT_OWNERSHIP_MISMATCH" + ); + assert.strictEqual(writeCalls, 0); +}); + +test("createwatchedcases rejects malformed GUID bindings before CRM access", async () => { + let tokenCalls = 0; + let relayCalls = 0; + let writeCalls = 0; + + const mod = loadModule("pages/api/endpoint/createwatchedcases_api.js", { + respondError: respondErrorMock, + respondSuccess: respondSuccessMock, + getServerSession: async () => ({ + user: { email: "test@example.com" } + }), + authOptions: () => ({}), + getToken: async () => { + tokenCalls += 1; + return { access_token: "token" }; + }, + relayGetData: async () => { + relayCalls += 1; + return { data: { value: [] } }; + }, + hashAPIPath: () => "&hash=expected", + axios: async () => { + writeCalls += 1; + return { data: {} }; + }, + consoleLogger: () => {} + }); + + const req = { + method: "POST", + body: { + "pinswg_WatchedCase@odata.bind": "/incidents(not-a-valid-guid)", + "pinswg_Contact@odata.bind": + "/contacts(22222222-2222-2222-2222-222222222222)" + } + }; + + const res = createRes(); + await mod.default(req, res); + + assert.strictEqual(res.state.statusCode, 400); + assert.strictEqual(res.state.jsonBody.error.code, "INVALID_BINDING_FORMAT"); + assert.strictEqual(tokenCalls, 0); + assert.strictEqual(relayCalls, 0); + assert.strictEqual(writeCalls, 0); +}); + +test("createwatchedcases rejects existing watchlist with mismatched ownership", async () => { + let writeCalls = 0; + + const ownContactID = "22222222-2222-2222-2222-222222222222"; + const otherContactID = "33333333-3333-3333-3333-333333333333"; + const caseID = "11111111-1111-1111-1111-111111111111"; + + const mod = loadModule("pages/api/endpoint/createwatchedcases_api.js", { + respondError: respondErrorMock, + respondSuccess: respondSuccessMock, + getServerSession: async () => ({ + user: { email: "test@example.com" } + }), + authOptions: () => ({}), + getToken: async () => ({ access_token: "token" }), + azureHeaders: () => ({ + headers: { Authorization: "Bearer token" } + }), + escapeODataString: (value) => value.replace(/'/g, "''"), + relayGetData: async ({ queryUrl }) => { + if (queryUrl.startsWith("contacts?")) { + return { + data: { value: [{ contactid: ownContactID }] } + }; + } + + if (queryUrl.startsWith("pinswg_watchlists?")) { + return { + data: { + value: [ + { + pinswg_watchlistid: + "44444444-4444-4444-4444-444444444444", + _pinswg_contact_value: otherContactID, + _pinswg_watchedcase_value: caseID + } + ] + } + }; + } + + throw new Error("Unexpected CRM query"); + }, + hashAPIPath: () => "&hash=expected", + axios: async () => { + writeCalls += 1; + return { data: {} }; + }, + consoleLogger: () => {} + }); + + const req = { + method: "POST", + body: { + "pinswg_WatchedCase@odata.bind": `/incidents(${caseID})`, + "pinswg_Contact@odata.bind": `/contacts(${ownContactID})` + } + }; + + const res = createRes(); + await mod.default(req, res); + + assert.strictEqual(res.state.statusCode, 403); + assert.strictEqual( + res.state.jsonBody.error.code, + "WATCHLIST_OWNERSHIP_MISMATCH" + ); + assert.strictEqual(writeCalls, 0); +}); + +test("createwatchedcases allows multiple existing watchlists for the same contact and case", async () => { + const writes = []; + + const contactID = "22222222-2222-2222-2222-222222222222"; + const caseID = "11111111-1111-1111-1111-111111111111"; + + const mod = loadModule("pages/api/endpoint/createwatchedcases_api.js", { + respondError: respondErrorMock, + respondSuccess: respondSuccessMock, + getServerSession: async () => ({ + user: { email: "test@example.com" } + }), + authOptions: () => ({}), + getToken: async () => ({ access_token: "token" }), + azureHeaders: () => ({ + headers: { Authorization: "Bearer token" } + }), + escapeODataString: (value) => value.replace(/'/g, "''"), + relayGetData: async ({ queryUrl }) => { + if (queryUrl.startsWith("contacts?")) { + return { + data: { value: [{ contactid: contactID }] } + }; + } + + if (queryUrl.startsWith("pinswg_watchlists?")) { + return { + data: { + value: [ + { + pinswg_watchlistid: + "44444444-4444-4444-4444-444444444444", + _pinswg_contact_value: contactID, + _pinswg_watchedcase_value: caseID + }, + { + pinswg_watchlistid: + "55555555-5555-5555-5555-555555555555", + _pinswg_contact_value: contactID, + _pinswg_watchedcase_value: caseID + } + ] + } + }; + } + + throw new Error("Unexpected CRM query"); + }, + hashAPIPath: () => "&hash=expected", + axios: async (config) => { + writes.push(config); + return { data: {} }; + }, + consoleLogger: () => {} + }); + + const req = { + method: "POST", + body: { + "pinswg_WatchedCase@odata.bind": `/incidents(${caseID})`, + "pinswg_Contact@odata.bind": `/contacts(${contactID})` + } + }; + + const res = createRes(); + await mod.default(req, res); + + assert.strictEqual(res.state.statusCode, 200); + assert.strictEqual(writes.length, 1); + assert.strictEqual(writes[0].method, "patch"); + + assert.ok( + writes[0].url.includes( + "pinswg_watchlists(44444444-4444-4444-4444-444444444444)" + ) + ); +}); + +test("createwatchedcases creates a watched case for the authenticated contact", async () => { + const contactID = "22222222-2222-2222-2222-222222222222"; + const caseID = "11111111-1111-1111-1111-111111111111"; + const writes = []; + + const mod = loadModule("pages/api/endpoint/createwatchedcases_api.js", { + respondError: respondErrorMock, + respondSuccess: respondSuccessMock, + getServerSession: async () => ({ + user: { email: "test@example.com" } + }), + authOptions: () => ({}), + getToken: async () => ({ access_token: "token" }), + azureHeaders: () => ({ + headers: { Authorization: "Bearer token" } + }), + escapeODataString: (value) => value.replace(/'/g, "''"), + relayGetData: async ({ queryUrl }) => { + if (queryUrl.startsWith("contacts?")) { + return { + data: { value: [{ contactid: contactID }] } + }; + } + + if (queryUrl.startsWith("pinswg_watchlists?")) { + return { data: { value: [] } }; + } + + throw new Error("Unexpected CRM query"); + }, + hashAPIPath: () => "&hash=expected", + axios: async (config) => { + writes.push(config); + return { data: { created: true } }; + }, + consoleLogger: () => {} + }); + + const body = { + "pinswg_WatchedCase@odata.bind": `/incidents(${caseID})`, + "pinswg_Contact@odata.bind": `/contacts(${contactID})`, + pinswg_emailnotifications: true + }; + + const res = createRes(); + + await mod.default( + { + method: "POST", + body + }, + res + ); + + assert.strictEqual(res.state.statusCode, 200); + assert.strictEqual(writes.length, 1); + assert.strictEqual(writes[0].method, "post"); + assert.ok(writes[0].url.includes("pinswg_watchlists")); + + const writtenData = JSON.parse(writes[0].data); + + assert.strictEqual( + writtenData["pinswg_Contact@odata.bind"], + `/contacts(${contactID})` + ); + assert.strictEqual( + writtenData["pinswg_WatchedCase@odata.bind"], + `/incidents(${caseID})` + ); + assert.strictEqual(writtenData.pinswg_emailnotifications, true); +}); + +test("createwatchedcases updates a verified watchlist preserving representation fields", async () => { + const contactID = "22222222-2222-2222-2222-222222222222"; + const caseID = "11111111-1111-1111-1111-111111111111"; + const watchlistID = "44444444-4444-4444-4444-444444444444"; + const writes = []; + + const mod = loadModule("pages/api/endpoint/createwatchedcases_api.js", { + respondError: respondErrorMock, + respondSuccess: respondSuccessMock, + getServerSession: async () => ({ + user: { email: "test@example.com" } + }), + authOptions: () => ({}), + getToken: async () => ({ access_token: "token" }), + azureHeaders: () => ({ + headers: { Authorization: "Bearer token" } + }), + escapeODataString: (value) => value.replace(/'/g, "''"), + relayGetData: async ({ queryUrl }) => { + if (queryUrl.startsWith("contacts?")) { + return { + data: { value: [{ contactid: contactID }] } + }; + } + + if (queryUrl.startsWith("pinswg_watchlists?")) { + return { + data: { + value: [ + { + pinswg_watchlistid: watchlistID, + _pinswg_contact_value: contactID, + _pinswg_watchedcase_value: caseID + } + ] + } + }; + } + + throw new Error("Unexpected CRM query"); + }, + hashAPIPath: () => "&hash=expected", + axios: async (config) => { + writes.push(config); + return { data: { updated: true } }; + }, + consoleLogger: () => {} + }); + + const body = { + "pinswg_WatchedCase@odata.bind": `/incidents(${caseID})`, + "pinswg_Contact@odata.bind": `/contacts(${contactID})`, + pinswg_emailnotifications: true, + pinswg_representationsubmitted: true, + pinswg_representationtype: 1 + }; + + const res = createRes(); + + await mod.default({ method: "POST", body }, res); + + assert.strictEqual(res.state.statusCode, 200); + assert.strictEqual(writes.length, 1); + assert.strictEqual(writes[0].method, "patch"); + assert.ok(writes[0].url.includes(`pinswg_watchlists(${watchlistID})`)); + + const writtenData = JSON.parse(writes[0].data); + + assert.strictEqual(writtenData.pinswg_emailnotifications, true); + assert.strictEqual(writtenData.pinswg_representationsubmitted, true); + assert.strictEqual(writtenData.pinswg_representationtype, 1); + assert.strictEqual( + writtenData["pinswg_Contact@odata.bind"], + `/contacts(${contactID})` + ); +}); + +test("createwatchedcases preserves previous representations when submitting another", async () => { + const contactID = "22222222-2222-2222-2222-222222222222"; + const caseID = "11111111-1111-1111-1111-111111111111"; + const writes = []; + + const existingRecords = [ + { + pinswg_watchlistid: "44444444-4444-4444-4444-444444444444", + _pinswg_contact_value: contactID, + _pinswg_watchedcase_value: caseID, + pinswg_representationsubmitted: "2025-01-07T10:00:00Z", + pinswg_representationtype: 1 + }, + { + pinswg_watchlistid: "55555555-5555-5555-5555-555555555555", + _pinswg_contact_value: contactID, + _pinswg_watchedcase_value: caseID, + pinswg_representationsubmitted: "2025-01-09T14:00:00Z", + pinswg_representationtype: 2 + } + ]; + + const mod = loadModule("pages/api/endpoint/createwatchedcases_api.js", { + respondError: respondErrorMock, + respondSuccess: respondSuccessMock, + getServerSession: async () => ({ + user: { email: "test@example.com" } + }), + authOptions: () => ({}), + getToken: async () => ({ access_token: "token" }), + azureHeaders: () => ({ + headers: { Authorization: "Bearer token" } + }), + escapeODataString: (value) => value.replace(/'/g, "''"), + relayGetData: async ({ queryUrl }) => { + if (queryUrl.startsWith("contacts?")) { + return { + data: { value: [{ contactid: contactID }] } + }; + } + + if (queryUrl.startsWith("pinswg_watchlists?")) { + assert.ok(queryUrl.includes("pinswg_representationsubmitted")); + + return { + data: { value: existingRecords } + }; + } + + throw new Error("Unexpected CRM query"); + }, + hashAPIPath: () => "&hash=expected", + axios: async (config) => { + writes.push(config); + return { data: { created: true } }; + }, + consoleLogger: () => {} + }); + + const submissionDate = "2025-01-14T09:30:00Z"; + + const body = { + "pinswg_WatchedCase@odata.bind": `/incidents(${caseID})`, + "pinswg_Contact@odata.bind": `/contacts(${contactID})`, + pinswg_representationsubmitted: submissionDate, + pinswg_representationtype: 3 + }; + + const res = createRes(); + + await mod.default({ method: "POST", body }, res); + + assert.strictEqual(res.state.statusCode, 200); + assert.strictEqual(writes.length, 1); + + // A new submission must not PATCH a historical representation. + assert.strictEqual(writes[0].method, "post"); + assert.ok(writes[0].url.includes("pinswg_watchlists")); + assert.ok( + !writes[0].url.includes( + "pinswg_watchlists(44444444-4444-4444-4444-444444444444)" + ) + ); + + const writtenData = JSON.parse(writes[0].data); + + assert.strictEqual( + writtenData.pinswg_representationsubmitted, + submissionDate + ); + assert.strictEqual(writtenData.pinswg_representationtype, 3); + assert.strictEqual( + writtenData["pinswg_Contact@odata.bind"], + `/contacts(${contactID})` + ); + + // Neither historical submission was modified. + assert.strictEqual( + existingRecords[0].pinswg_representationsubmitted, + "2025-01-07T10:00:00Z" + ); + assert.strictEqual( + existingRecords[1].pinswg_representationsubmitted, + "2025-01-09T14:00:00Z" + ); +}); + const WATCHED_CASE_ID = "11111111-1111-1111-1111-111111111111"; const CONTACT_ID = "22222222-2222-2222-2222-222222222222"; const OTHER_CONTACT_ID = "33333333-3333-3333-3333-333333333333";