Adding esslGetUserDetails
This commit is contained in:
parent
e517367967
commit
47bd8610d2
18
functions/package-lock.json
generated
18
functions/package-lock.json
generated
@ -25,13 +25,15 @@
|
||||
"node-fetch": "^2.7.0",
|
||||
"pdfjs-dist": "^5.0.375",
|
||||
"pdfmake": "^0.2.20",
|
||||
"twilio": "^5.4.0"
|
||||
"twilio": "^5.4.0",
|
||||
"xmldom": "^0.6.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/long": "^5.0.0",
|
||||
"@types/mime-types": "^2.1.4",
|
||||
"@types/node": "^22.13.14",
|
||||
"@types/pdfmake": "^0.2.11",
|
||||
"@types/xmldom": "^0.1.34",
|
||||
"firebase-functions-test": "^3.1.0",
|
||||
"typescript": "^5.8.2"
|
||||
},
|
||||
@ -2946,6 +2948,12 @@
|
||||
"integrity": "sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==",
|
||||
"optional": true
|
||||
},
|
||||
"node_modules/@types/xmldom": {
|
||||
"version": "0.1.34",
|
||||
"resolved": "https://registry.npmjs.org/@types/xmldom/-/xmldom-0.1.34.tgz",
|
||||
"integrity": "sha512-7eZFfxI9XHYjJJuugddV6N5YNeXgQE1lArWOcd1eCOKWb/FGs5SIjacSYuEJuwhsGS3gy4RuZ5EUIcqYscuPDA==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@types/yargs": {
|
||||
"version": "17.0.33",
|
||||
"resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.33.tgz",
|
||||
@ -8324,6 +8332,14 @@
|
||||
"resolved": "https://registry.npmjs.org/sax/-/sax-1.4.1.tgz",
|
||||
"integrity": "sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg=="
|
||||
},
|
||||
"node_modules/xmldom": {
|
||||
"version": "0.6.0",
|
||||
"resolved": "https://registry.npmjs.org/xmldom/-/xmldom-0.6.0.tgz",
|
||||
"integrity": "sha512-iAcin401y58LckRZ0TkI4k0VSM1Qg0KGSc3i8rU+xrxe19A/BN1zHyVSJY7uoutVlaTSzYyk/v5AmkewAP7jtg==",
|
||||
"engines": {
|
||||
"node": ">=10.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/y18n": {
|
||||
"version": "5.0.8",
|
||||
"resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",
|
||||
|
||||
@ -32,13 +32,15 @@
|
||||
"node-fetch": "^2.7.0",
|
||||
"pdfjs-dist": "^5.0.375",
|
||||
"pdfmake": "^0.2.20",
|
||||
"twilio": "^5.4.0"
|
||||
"twilio": "^5.4.0",
|
||||
"xmldom": "^0.6.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/long": "^5.0.0",
|
||||
"@types/mime-types": "^2.1.4",
|
||||
"@types/node": "^22.13.14",
|
||||
"@types/pdfmake": "^0.2.11",
|
||||
"@types/xmldom": "^0.1.34",
|
||||
"firebase-functions-test": "^3.1.0",
|
||||
"typescript": "^5.8.2"
|
||||
},
|
||||
|
||||
7
functions/src/dooraccess/doorAccessUser.ts
Normal file
7
functions/src/dooraccess/doorAccessUser.ts
Normal file
@ -0,0 +1,7 @@
|
||||
export type DoorAccessUser = {
|
||||
name: string;
|
||||
location: string;
|
||||
role: string;
|
||||
expireFrom: Date | null;
|
||||
expireTo: Date | null;
|
||||
};
|
||||
162
functions/src/dooraccess/essl.ts
Normal file
162
functions/src/dooraccess/essl.ts
Normal file
@ -0,0 +1,162 @@
|
||||
import { onRequest } from "firebase-functions/https";
|
||||
import { DoorAccessUser } from "./doorAccessUser";
|
||||
import { Request } from "firebase-functions/v2/https";
|
||||
import { Response } from "express";
|
||||
import { getCorsHandler } from "../shared/middleware";
|
||||
import { getLogger } from "../shared/config";
|
||||
import { DOMParser } from 'xmldom';
|
||||
|
||||
const logger = getLogger();
|
||||
const corsHandler = getCorsHandler();
|
||||
|
||||
const escapeXml = (str: string) => {
|
||||
return str
|
||||
.replace(/&/g, '&')
|
||||
.replace(/</g, '<')
|
||||
.replace(/>/g, '>')
|
||||
.replace(/"/g, '"')
|
||||
.replace(/'/g, ''');
|
||||
};
|
||||
|
||||
function createGetEmployeeDetailsRequest(username: string, password: string, employeeCode: string) {
|
||||
const soapRequest = `<?xml version="1.0" encoding="utf-8"?>
|
||||
<soap12:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap12="http://www.w3.org/2003/05/soap-envelope">
|
||||
<soap12:Body>
|
||||
<GetEmployeeDetails xmlns="http://tempuri.org/">
|
||||
<UserName>${escapeXml(username)}</UserName>
|
||||
<Password>${escapeXml(password)}</Password>
|
||||
<EmployeeCode>${escapeXml(employeeCode)}</EmployeeCode>
|
||||
</GetEmployeeDetails>
|
||||
</soap12:Body>
|
||||
</soap12:Envelope>`;
|
||||
|
||||
return soapRequest;
|
||||
}
|
||||
|
||||
function parseGetEmployeeDetailsResponse(soapResponse: string): DoorAccessUser {
|
||||
const parser = new DOMParser();
|
||||
const xmlDoc = parser.parseFromString(soapResponse, "text/xml");
|
||||
if (xmlDoc.documentElement.tagName !== 'soap:Envelope') {
|
||||
throw new Error("Invalid SOAP response");
|
||||
}
|
||||
if (null == xmlDoc.documentElement.firstChild) {
|
||||
throw new Error("Invalid SOAP response");
|
||||
}
|
||||
|
||||
let currentElement = xmlDoc.documentElement.firstChild as HTMLElement;
|
||||
if (currentElement.tagName !== 'soap:Body') {
|
||||
throw new Error("Invalid SOAP response");
|
||||
}
|
||||
|
||||
currentElement = currentElement.firstChild as HTMLElement;
|
||||
if (currentElement.tagName !== 'GetEmployeeDetailsResponse') {
|
||||
throw new Error("Invalid SOAP response");
|
||||
}
|
||||
|
||||
currentElement = currentElement.firstChild as HTMLElement;
|
||||
if (currentElement.tagName !== 'GetEmployeeDetailsResult') {
|
||||
throw new Error("Invalid SOAP response");
|
||||
}
|
||||
|
||||
const resultText = currentElement.textContent;
|
||||
if (!resultText) {
|
||||
throw new Error("GetEmployeeDetailsResult is empty");
|
||||
}
|
||||
|
||||
const userDetails: DoorAccessUser =
|
||||
{
|
||||
name: '',
|
||||
location: '',
|
||||
role: '',
|
||||
expireFrom: null,
|
||||
expireTo: null
|
||||
};
|
||||
const pairs = resultText.split(',');
|
||||
pairs.forEach(pair => {
|
||||
const [key, value] = pair.split('=');
|
||||
if (key && value !== undefined) {
|
||||
const cleanKey = key.trim();
|
||||
const cleanValue = value.trim();
|
||||
switch (cleanKey) {
|
||||
case 'EmployeeName':
|
||||
userDetails.name = cleanValue;
|
||||
break;
|
||||
case 'EmployeeLocation':
|
||||
userDetails.location = cleanValue;
|
||||
break;
|
||||
case 'EmployeeRole':
|
||||
userDetails.role = cleanValue;
|
||||
break;
|
||||
case 'EmployeeExpiryFrom':
|
||||
userDetails.expireFrom = new Date(cleanValue);
|
||||
break;
|
||||
case 'EmployeeExpiryTo':
|
||||
userDetails.expireTo = new Date(cleanValue);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return userDetails;
|
||||
}
|
||||
|
||||
async function sendSoapRequest(soapRequest: string, endpoint: string) {
|
||||
try {
|
||||
const headers: any = {
|
||||
'Content-Type': 'application/soap+xml; charset=utf-8',
|
||||
'Content-Length': soapRequest.length.toString()
|
||||
};
|
||||
|
||||
const response = await fetch(endpoint, {
|
||||
method: 'POST',
|
||||
headers: headers,
|
||||
body: soapRequest
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(`HTTP error! status: ${response.status}`);
|
||||
}
|
||||
|
||||
return await response.text();
|
||||
} catch (error: any) {
|
||||
throw new Error(`SOAP request failed: ${error.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
async function getUserDetails(username: string,
|
||||
password: string,
|
||||
employeeCode: string, endpoint: string) {
|
||||
const soapRequest = createGetEmployeeDetailsRequest(username, password, employeeCode);
|
||||
const soapResponse = await sendSoapRequest(soapRequest, endpoint);
|
||||
const parsedResponse = parseGetEmployeeDetailsResponse(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)) {
|
||||
throw new Error('Missing username or password');
|
||||
}
|
||||
if (!employeeCode) {
|
||||
throw new Error('Missing employee code');
|
||||
}
|
||||
if (!endpoint) {
|
||||
throw new Error('Missing endpoint');
|
||||
}
|
||||
const userDetails = await getUserDetails(username, password, employeeCode, endpoint);
|
||||
response.send(userDetails);
|
||||
} catch (error: any) {
|
||||
logger.error(error);
|
||||
response.status(500).send({ error: error.message });
|
||||
}
|
||||
})
|
||||
});
|
||||
1
functions/src/dooraccess/index.ts
Normal file
1
functions/src/dooraccess/index.ts
Normal file
@ -0,0 +1 @@
|
||||
export { esslGetUserDetails } from './essl';
|
||||
@ -63,7 +63,7 @@ async function sendSimpleEmail(data: EmailRequest, recipients: string[]) {
|
||||
|
||||
async function sendEmailWithAttachments(data: EmailRequest, recipients: string[]) {
|
||||
const ses = new SESClient({
|
||||
region: 'ap-south-1',
|
||||
region: '#{SERVICES_RGN}#',
|
||||
credentials: {
|
||||
accessKeyId: process.env.AWS_ACCESS_KEY_ID || '',
|
||||
secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY || ''
|
||||
|
||||
@ -17,3 +17,4 @@ export { processNotificationOnCreate } from './notifications';
|
||||
export * from './payments';
|
||||
export { getPlaceDetails, getPlacesAutocomplete } from './places';
|
||||
export { registerClient } from './users';
|
||||
export { esslGetUserDetails } from './dooraccess';
|
||||
|
||||
Loading…
Reference in New Issue
Block a user