'use strict'; const db = require('../models/index'); const fs = require('fs'); const csv = require('csv-parser'); const moment = require('moment'); const { USER_ENTRY_EVENT, ENABLE_PASSAGE_MODE, DISABLE_PASSAGE_MODE, USER_UNLOCKED_DOOR, USER_LOCKED_DOOR, VALID_CSV_HEADERS, csvParserErrors, } = require('../constants/constants'); const { fetchAllMembers, findMember } = require('../services/officeRnD/members'); const parseDoorLockDataFile = (file) => { return new Promise ((resolve, reject) => { const results = []; const errors = []; const unknownMembers = []; let isValidFile = true; fetchAllMembers() .then(() => { fs.createReadStream(file.path) .pipe(csv({ mapHeaders: ({ header, index }) => header.trim().toLowerCase(), mapValues: ({ header, index, value }) => value.trim() })) .on('headers', (headers) => { const sortedValidHeadersArray = VALID_CSV_HEADERS.concat().sort(); const sortedParsedHeadersArray = headers.map(header => header.trim()).sort(); let validHeaders = true; if (sortedParsedHeadersArray.length !== sortedValidHeadersArray.length) { validHeaders = false; }else { for (let i = 0; i < sortedValidHeadersArray.length; i++){ validHeaders = validHeaders && (sortedValidHeadersArray[i] === sortedParsedHeadersArray[i]); } } if (!validHeaders){ isValidFile = false; errors.push({ error: csvParserErrors.INVALID_HEADERS, details: `Expected headers : ${JSON.stringify(VALID_CSV_HEADERS)}`, file: file.name, }); } }) .on('data', (data) => { if (!isValidFile) { return; } const eventType = data.event.trim(); if ([USER_ENTRY_EVENT, ENABLE_PASSAGE_MODE, DISABLE_PASSAGE_MODE].includes(eventType)){ results.push(data); } }) .on('end', () => { const parsedData = []; let i = 0; while (i < results.length){ //Verify pair //First entry type should be user entry and second should be enable / disable passage const firstEntry = results[i]; const secondEntry = results[i+1]; if (firstEntry && (firstEntry.event === USER_ENTRY_EVENT)){ const memberObject = findMember(firstEntry.name); if (!memberObject){ //Check if member is already labeled as unknown const unknownMember = unknownMembers.find((member) => member.details === firstEntry.name); if (!unknownMember){ unknownMembers.push({ error: csvParserErrors.UNKNOWN_MEMBER, details: firstEntry.name, file: file.name, }); } } if (secondEntry && (secondEntry.event === ENABLE_PASSAGE_MODE || secondEntry.event === DISABLE_PASSAGE_MODE)){ const event = (secondEntry.event === ENABLE_PASSAGE_MODE) ? USER_UNLOCKED_DOOR : USER_LOCKED_DOOR; const dateTimeString = `${firstEntry.date} ${firstEntry.time}`; const timestamp = moment.utc(dateTimeString, 'MM/DD/YY HH:mm:ss A').toISOString(); //Verify that member is registered in OfficeRnD system if (memberObject){ const entryData = { memberName: firstEntry.name, memberNumber: firstEntry['user no'], memberId: memberObject.memberId, timestamp, event, }; parsedData.push(entryData); } i+=2; } else { errors.push({ error: csvParserErrors.INVALID_ENTRY_EXPECTED_PASSAGE_MODE, details: firstEntry, file: file.name, }); i+=1; } } else { errors.push({ error: csvParserErrors.INVALID_ENTRY_EXPECTED_USER, details: firstEntry, file: file.name, }); i+=1; } } resolve({ parsedData, unknownMembers, errors }); }); }) .catch((error) => { reject(error); }); }); }; const writeDoorLockEvent = (entry) => { db.doorLockEvent.findOrCreate({where: {...entry}, defaults: {...entry}}) .then() .catch(); }; module.exports = { parseDoorLockDataFile, writeDoorLockEvent, };