diff --git a/scheduler.js b/asessorScheduler.js similarity index 97% rename from scheduler.js rename to asessorScheduler.js index 9a8af4bba8543a7cfa6555386d92fb4af26fc838..347aa93d692a01ee823590bc26de872fc650b7f4 100644 --- a/scheduler.js +++ b/asessorScheduler.js @@ -9,7 +9,7 @@ const UPDATE_ASSESSMENT_ENDPOINT = "/rest/assessorUpdateForm" const SCHEDULES_ENDPOINT = "/rest/getAssessmentSchedule"; const TARGET_URL = process.env.TARGET_URL || "https://hasura.upsmfac.org"; const REACT_APP_NODE_URL = process.env.REACT_APP_API_URL || "https://uphrh.in/api/api"; -const AUTH_TOKEN = process.env.REACT_APP_AUTH_TOKEN || "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJSR3RkMkZzeG1EMnJER3I4dkJHZ0N6MVhyalhZUzBSSyJ9.kMLn6177rvY53i0RAN3SPD5m3ctwaLb32pMYQ65nBdA"; +const AUTH_TOKEN = process.env.REACT_APP_AUTH_TOKEN; // Creating an Axios instance with custom headers const axiosInstance = axios.create({ diff --git a/backgroundWorker.js b/backgroundWorker.js index 53c776bff0e038b9077182a18793cab0e12f480b..a5470edc8c463f7a0c42f133342db45f925df95d 100644 --- a/backgroundWorker.js +++ b/backgroundWorker.js @@ -1,17 +1,15 @@ import axios from "axios"; import async from "async"; const targetURL = process.env.TARGET_URL || "https://hasura.upsmfac.org"; -const notificationURL = process.env.REACT_APP_API_URL || "https://uphrh.in/api/api"; -const emailAuthToken = process.env.REACT_APP_AUTH_TOKEN; +const REACT_APP_NODE_URL = process.env.REACT_APP_API_URL || "https://uphrh.in/api/api"; +const AUTH_TOKEN = process.env.REACT_APP_AUTH_TOKEN; const getBulkUploadAssessorSchedule = '/api/rest/getBulkUploadAssessorSchedule'; const filterAssessments = '/api/rest/filterAssessments'; -const getUsersForSchedulingAssessment = '/api/rest/getUsersForSchedulingAssessment'; const addAssessmentSchedule = '/api/rest/addAssessmentSchedule'; const addInstituteCourse = '/api/rest/addInstituteCourse'; const addEvents = '/api/rest/addEvents'; const updateForm = '/api/rest/updateForm'; -const getApplicantDeviceId = '/api/rest/getApplicantDeviceId'; const notify = '/email/notify'; const getFormSubmissionsByFormIds = '/api/rest/getFormSubmissionsByFormIds'; const updateStatusToBulkUpload = '/api/rest/updateStatusToBulkUpload'; @@ -131,18 +129,24 @@ const getAdminDetails = async (adminId) => { const sendEmailNotification = async (postData) => { return new Promise(async(resolve) => { - const res = await axiosInstance.post( - notificationURL + notify, - postData, - { - headers: { - "Content-Type": "application/json", - Authorization: emailAuthToken, - }, + try { + //console.log(postData); + const res = await axiosInstance.post( + REACT_APP_NODE_URL + notify, + postData, + { + headers: { + "Content-Type": "application/json", + Authorization: AUTH_TOKEN, + }, + } + ); + resolve( res); + } catch (error) { + console.error('Error sendEmailNotification:', error.message); + throw error; } - ); - resolve( res); -}); + }); }; const getFormSubmissionsByFormId = (arr) => { return new Promise(async(resolve) => { @@ -182,6 +186,24 @@ function findDuplicateRecords(array, attribute1, attribute2) { return duplicates; } +function findDuplicateRecordsByStatus(array, attribute1, attribute2, attribute3) { + + var duplicates = array.filter((item, index, self) => { + return ( + index !== self.findIndex( + (innerItem) => + innerItem[attribute1] === item[attribute1] && + (innerItem[attribute3] !== item[attribute3] + )&& + item[attribute2] === 'Pending' + ) + ); + }); + + const maxId = duplicates.reduce((max, current) => (current.id > max ? current.id : max), array[0].id); + duplicates = duplicates.filter((record) => record.id !== maxId); + return duplicates; +} function getDatesFromTodayTo90Days() { const currentDate = new Date(); @@ -342,7 +364,7 @@ const addAssessorSchedule = (formSubmissionObj, element, assessorObj, callback)= ); } catch (error) { console.error('Error addAssessorSchedule:', error.message); - throw error; + //throw error; } } @@ -356,6 +378,7 @@ const executeBulkUpload = (bulkUploadData, emailTableRows, adminId, formSubData callback1(null,"success",emailTableRows, adminId); }else{ bulkUploadData.forEach((element) => { + adminId = element.uploaded_by; async.waterfall([ function checkAssessor(callback2){ var isUpdate = false; @@ -435,14 +458,18 @@ const findMissingRecords = (object1, object2, key1,key2) => { }; const removeDuplicatesFromBulkUpload = (bulkUploadData, emailTableRows, callback) =>{ // Find duplicates based on the "application_id" attribute - const duplicates = findDuplicateRecords(bulkUploadData, 'application_id','process_id'); + var duplicates = findDuplicateRecords(bulkUploadData, 'application_id','process_id'); + const duplicatesByStatus = findDuplicateRecordsByStatus(bulkUploadData, 'application_id','status','process_id'); var itemsProcessed = 0; var adminId = ""; - console.log("duplicates "+ duplicates.length+" : "+bulkUploadData.length); + console.log("duplicates in request file"+ duplicates.length+" : "+bulkUploadData.length); + console.log("old duplicates in bulk upload table"+ duplicatesByStatus.length+" : "+bulkUploadData.length); + duplicates.push(...duplicatesByStatus); if(duplicates.length === 0){ callback(null,"success",bulkUploadData,emailTableRows,adminId); }else{ duplicates.forEach(element => { + adminId = element.uploaded_by; async.waterfall([ function updatedbrec(callback1){ var updateStatus = "Failed"; @@ -473,6 +500,7 @@ const removeInvalidFormSubmissionIds = async (bulkUploadData, emailTableRows, ad callback(null,"success",bulkUploadData,emailTableRows,adminId); } else { missingRecords.forEach(async (element) => { + adminId = element.uploaded_by; async.waterfall([ function updatedbrec(callback1){ var updateRemarks = "Form Application id is not existing in system or payment is not complete."; @@ -546,12 +574,12 @@ const performBackgroundTask = async () => { var adminEmail = adminEmailTemplate.replace("${adminName}", adminDetails[0].full_name); adminEmail = adminEmail.replace("${emailTableRows}", emailTableRows.toString()); const adminEmailData = { - "recipientEmail":[adminDetails[0].email,"reshmi.nair@tarento.com"], + "recipientEmail":[adminDetails[0].email], "emailSubject":"Assessor Upload Status", "emailBody":adminEmail }; sendEmailNotification(adminEmailData); - console.log('Admin notification sent..'); + console.log('Admin notification sent..'+adminDetails[0].email); } } }); @@ -562,7 +590,6 @@ const performBackgroundTask = async () => { // Process the API response } catch (error) { console.error('Error making API call:', error.message); - throw error; } } diff --git a/index.js b/index.js index 6d66070c08faa9596b82a8b12e6e97e9292dd79a..8da0220a4d97a9b9876205f30c5fbd3d0a777c02 100644 --- a/index.js +++ b/index.js @@ -2,7 +2,7 @@ import express from "express"; import { createProxyMiddleware } from "http-proxy-middleware"; import endpoints from "./endpoints/endpoints.js"; import easyPay from "./utils/easypay.js"; -import scheduledJob from "./scheduler.js"; +import scheduledJob from "./asessorScheduler.js"; import axios from "axios"; const app = express(); @@ -162,7 +162,7 @@ app.post('/upload/assessor/schedule', upload.single('file'), async(req, res) => try { const processId = uuidv4(); - const validfileHeaders = ["form_id","form_title","application_type","course_type","assessor_id"]; + const validfileHeaders = ["form_id","form_title","application_type","course_type","date","form_status","payment_status","assessor_id"]; const { userId } = req.body; // Get data from the uploaded file @@ -195,6 +195,13 @@ app.post('/upload/assessor/schedule', upload.single('file'), async(req, res) => cellValue = cell.value; rowData[header [colNumber]] = cellValue; } + if(cellValue.length<=1){ + console.error("Invalid data format"); + throw new BadRequestError("Invalid data format : "+cellValue ); + } + }else{ + console.error("Invalid file format"); + throw new BadRequestError("Invalid file format : "+header [colNumber] ); } } }); @@ -203,39 +210,57 @@ app.post('/upload/assessor/schedule', upload.single('file'), async(req, res) => rowData["assessor_id"]=0; } results.push(rowData); + }else{ + //Ignore the empty row } - }); - results.forEach((item) => { - item["process_id"]=processId; - item["uploaded_by"]=userId; - item["status"]="Pending"; - item["uploaded_date"]=new Date().toLocaleString(); - }); - //{"assessor_schedule_bulk_upload": [{"id": 1,"process_id":1,"uploaded_by":"system","uploaded_date": "2023-11-17","application_id":234,"assessor_id":232}]} - const bulkUploadDetails = bulkUpload({"assessor_schedule_bulk_upload":results}); - - const worker = new Worker('./backgroundWorker.js'); - worker.on('message', (message) => { - console.log(`Background Worker Message: ${message}`); - }); - worker.on('error', (error) => { - console.error(`Background Worker Error: ${error}`); - }); - worker.on('exit', (code) => { - console.log(`Background Worker exited with code ${code}`); - }); + }); + if(results.length===0){ + throw new BadRequestError("Invalid file format"); + } + results.forEach((item) => { + item["process_id"]=processId; + item["uploaded_by"]=userId; + item["status"]="Pending"; + item["uploaded_date"]=new Date().toLocaleString(); + }); + //{"assessor_schedule_bulk_upload": [{"id": 1,"process_id":1,"uploaded_by":"system","uploaded_date": "2023-11-17","application_id":234,"assessor_id":232}]} + const bulkUploadDetails = bulkUpload({"assessor_schedule_bulk_upload":results}); - // Process the parsed CSV data - res.json({ data: results }); - + const worker = new Worker('./backgroundWorker.js'); + worker.on('message', (message) => { + console.log(`Background Worker Message: ${message}`); + }); + worker.on('error', (error) => { + console.error(`Background Worker Error: ${error}`); + }); + worker.on('exit', (code) => { + console.log(`Background Worker exited with code ${code}`); + }); + // Process the parsed CSV data + return res.json({ data: results }); + } catch (error) { + if (error instanceof BadRequestError) { + console.error(`Caught BadRequestError: ${error.message}`); + console.error(`HTTP Status Code: ${error.statusCode}`); + res.status(400).json({ success: false, error: error.message }); + } else { + console.error("Error:", error); console.error("Error message:", error.message); res.status(500).json({ success: false, error: error.message }); + } } }); - +class BadRequestError extends Error { + constructor(message) { + super(message); + this.name = 'BadRequestError'; + this.statusCode = 400; // HTTP status code for Bad Request + Error.captureStackTrace(this, this.constructor); + } +} // Custom Stream class to create a readable stream from a buffer class BufferStream { constructor(buffer) {