import { consoleLogger } from "../../../actions/core/logger"; import { respondError, respondSuccess } from "../middleware/apiResponse"; import { updateCrmContact } from "../../../lib/server/updateCrmContact"; import { getServerSession } from "next-auth/next"; import { authOptions } from "../auth/[...nextauth]"; import { getToken } from "../../../actions/core/token"; import { relayGetData } from "../middleware/relayForwarding"; import { azureHeaders } from "../../../actions/core/headers"; import { escapeODataString } from "../../../actions/core/guards"; 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 ALLOWED_ACCOUNT_FIELDS = new Set([ "pinswg_preferredlanguage", "firstname", "lastname", "telephone1", "pinswg_companyname", "address1_line1", "address1_line2", "address1_city", "address1_county", "address1_postalcode" ]); export default async function ApiProxy(req, res) { if (req.method !== "POST") { res.setHeader("Allow", "POST"); return respondError(res, { status: 405, code: "METHOD_NOT_ALLOWED", message: "Method not allowed" }); } const session = await getServerSession(req, res, authOptions(req, res)); if ( typeof session?.user?.email !== "string" || session.user.email.trim().length === 0 ) { return respondError(res, { status: 401, code: "UNAUTHENTICATED", message: "Authentication required" }); } const contactId = req.query.contactId; if (typeof contactId !== "string" || !GUID_PATTERN.test(contactId.trim())) { return respondError(res, { status: 400, code: "INVALID_CONTACT_ID", message: "A valid contactId is required" }); } if ( !req.body || typeof req.body !== "object" || Array.isArray(req.body) || Object.keys(req.body).length === 0 ) { return respondError(res, { status: 400, code: "ACCOUNT_UPDATE_PAYLOAD_REQUIRED", message: "Account update payload is required" }); } try { const token = await getToken(); const escapedEmail = escapeODataString(session.user.email); 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 updatePayload = Object.fromEntries( Object.entries(req.body).filter(([field]) => ALLOWED_ACCOUNT_FIELDS.has(field) ) ); if (Object.keys(updatePayload).length === 0) { return respondError(res, { status: 400, code: "NO_ALLOWED_ACCOUNT_FIELDS", message: "No permitted account fields supplied" }); } const data = await updateCrmContact(contactId.trim(), updatePayload); return respondSuccess(res, data); } catch (error) { consoleLogger(error); return respondError(res, { status: 400, code: "ACCOUNT_UPDATE_FAILED", message: "Failed to update account" }); } }