From bb3e966dafdefb5d43f6035a4b3663a310d78d7c Mon Sep 17 00:00:00 2001 From: Benoy Bose Date: Mon, 9 Jun 2025 14:24:19 +0530 Subject: [PATCH] Adding updateEmployeeEx --- functions/src/dooraccess/essl.ts | 165 +++++++++++++++++++++++++++- functions/src/dooraccess/index.ts | 2 +- functions/src/email/sendEmailSES.ts | 2 +- functions/src/index.ts | 2 +- 4 files changed, 162 insertions(+), 9 deletions(-) diff --git a/functions/src/dooraccess/essl.ts b/functions/src/dooraccess/essl.ts index 231b06a..c45ea64 100644 --- a/functions/src/dooraccess/essl.ts +++ b/functions/src/dooraccess/essl.ts @@ -9,6 +9,23 @@ import { DOMParser } from 'xmldom'; const logger = getLogger(); const corsHandler = getCorsHandler(); +export interface GetEmployeeDetailsRquest { + employeeCode: string; +} + +export interface UpdateEmployeeExRequest { + employeeCode: string; + employeeName: string; + employeeLocation: string; + employeeRole: string; + employeeVerificationType: string; + employeeExpiryFrom: string; + employeeExpiryTo: string; + employeeCardNumber: string; + groupId: string; + employeePhoto: string; +} + const escapeXml = (str: string) => { return str .replace(/&/g, '&') @@ -102,6 +119,52 @@ function parseGetEmployeeDetailsResponse(soapResponse: string): DoorAccessUser { return userDetails; } +function isValidDateString(dateString: string): boolean { + const dateRegex = /^\d{4}\-\d{2}\-\d{2}$/; + return dateRegex.test(dateString); +} + +function createUpdateEmployeeExRequest(username: string, password: string, request: UpdateEmployeeExRequest) { + + if (!username || !password || !request.employeeCode || !request.employeeName || !request.employeeLocation) { + throw new Error('Missing required fields'); + } + + if (!isValidDateString(request.employeeExpiryFrom) || !isValidDateString(request.employeeExpiryTo)) { + throw new Error('Invalid date format'); + } + + const soapRequest = ` + + + + ${escapeXml(username)} + ${escapeXml(password)} + ${escapeXml(request.employeeCode)} + ${escapeXml(request.employeeName)} + ${escapeXml(request.employeeLocation)} + ${escapeXml(request.employeeRole)} + Card + ${escapeXml(request.employeeExpiryFrom)} + ${escapeXml(request.employeeExpiryTo)} + ${escapeXml(request.employeeCardNumber)} + + + + + +`; + return soapRequest; +} + +function parseUpdateEmployeeExResponse(soapResponse: string): string | null { + const parser = new DOMParser(); + const xmlDoc = parser.parseFromString(soapResponse, "text/xml"); + const currentElement = xmlDoc.documentElement.firstChild as HTMLElement; + const resultText = currentElement.textContent; + return resultText; +} + async function sendSoapRequest(soapRequest: string, endpoint: string) { try { const headers: any = { @@ -134,24 +197,63 @@ async function getUserDetails(username: string, return parsedResponse; } +async function updateEmployeeEx(username: string, + password: string, + request: UpdateEmployeeExRequest, + endpoint: string) { + const soapRequest = createUpdateEmployeeExRequest(username, password, request); + const soapResponse = await sendSoapRequest(soapRequest, endpoint); + const parsedResponse = parseUpdateEmployeeExResponse(soapResponse); + return parsedResponse; +} + export const esslGetUserDetails = onRequest({ region: '#{SERVICES_RGN}#' }, async (request: Request, response: Response) => { return corsHandler(request, response, async () => { try { - const username = request.body.username; - const password = request.body.password; - const employeeCode = request.body.employeeCode; - const endpoint = request.body.endpoint; - if ((!username) || (!password)) { + let username: string | null = request.body.username as string; + let password: string | null = request.body.password as string; + let endpoint: string | null = request.body.endpoint as string; + let gymId: string | null = request.body.gymId as string; + + const getEmployeeDetailsRequest = request.body.params as GetEmployeeDetailsRquest; + + if (!username) { throw new Error('Missing username or password'); } + username = username.trim(); + if (!password) { + if (!gymId) { + throw new Error('Missing password or gymId'); + } + // todo: Get password from gym configuration by decrypting with private key + } + password = password.trim(); + if (!getEmployeeDetailsRequest) { + throw new Error('Missing request params'); + } + const employeeCode = getEmployeeDetailsRequest.employeeCode; if (!employeeCode) { - throw new Error('Missing employee code'); + throw new Error('Missing employeeCode'); } if (!endpoint) { throw new Error('Missing endpoint'); } + if (!endpoint || endpoint.trim() === '') { + throw new Error('Missing endpoint'); + } + try { + new URL(endpoint); + } catch (_) { + throw new Error('Endpoint is not a valid URI or URL'); + } + if (!endpoint.endsWith('/webservice.asmx')) { + if (endpoint.endsWith('/')) { + endpoint = endpoint.substring(0, endpoint.length - 1); + } + endpoint += '/webservice.asmx'; + } const userDetails = await getUserDetails(username, password, employeeCode, endpoint); response.send(userDetails); } catch (error: any) { @@ -160,3 +262,54 @@ export const esslGetUserDetails = onRequest({ } }) }); + +export const esslUpdateUser = onRequest({ + region: '#{SERVICES_RGN}#' +}, async (request: Request, response: Response) => { + return corsHandler(request, response, async () => { + try { + let username: string | null = request.body.username as string; + let password: string | null = request.body.password as string; + let endpoint: string | null = request.body.endpoint as string; + let gymId: string | null = request.body.gymId as string; + + const updateEmployeeExRequest = request.body.params as UpdateEmployeeExRequest; + if (!username) { + throw new Error('Missing username or password'); + } + username = username.trim(); + if (!password) { + if (!gymId) { + throw new Error('Missing password or gymId'); + } + // todo: Get password from gym configuration by decrypting with private key + } + if (!endpoint) { + throw new Error('Missing endpoint'); + } + endpoint = endpoint.trim(); + if (!endpoint || endpoint.trim() === '') { + throw new Error('Missing endpoint'); + } + try { + new URL(endpoint); + } catch (_) { + throw new Error('Endpoint is not a valid URI or URL'); + } + if (!endpoint.endsWith('/webservice.asmx')) { + if (endpoint.endsWith('/')) { + endpoint = endpoint.substring(0, endpoint.length - 1); + } + endpoint += '/webservice.asmx'; + } + if (!updateEmployeeExRequest) { + throw new Error('Missing request params'); + } + const result = await updateEmployeeEx(username, password, updateEmployeeExRequest, endpoint); + response.send(result); + } catch (error: any) { + logger.error(error); + response.status(500).send({ error: error.message }); + } + }); +}); diff --git a/functions/src/dooraccess/index.ts b/functions/src/dooraccess/index.ts index a855858..497e0cb 100644 --- a/functions/src/dooraccess/index.ts +++ b/functions/src/dooraccess/index.ts @@ -1 +1 @@ -export { esslGetUserDetails } from './essl'; \ No newline at end of file +export { esslGetUserDetails, esslUpdateUser } from './essl'; \ No newline at end of file diff --git a/functions/src/email/sendEmailSES.ts b/functions/src/email/sendEmailSES.ts index 8d0437c..5efc40a 100644 --- a/functions/src/email/sendEmailSES.ts +++ b/functions/src/email/sendEmailSES.ts @@ -136,7 +136,7 @@ async function downloadFileFromUrl(url: string): Promise { } export const sendEmailSES = onRequest({ - region: 'asia-south1' + region: '#{SERVICES_RGN}#' }, (request: Request, response: Response) => { return corsHandler(request, response, async () => { try { diff --git a/functions/src/index.ts b/functions/src/index.ts index 12cacad..362d85d 100644 --- a/functions/src/index.ts +++ b/functions/src/index.ts @@ -17,4 +17,4 @@ export { processNotificationOnCreate } from './notifications'; export * from './payments'; export { getPlaceDetails, getPlacesAutocomplete } from './places'; export { registerClient } from './users'; -export { esslGetUserDetails } from './dooraccess'; +export { esslGetUserDetails, esslUpdateUser } from './dooraccess';