Created
June 3, 2024 18:30
-
-
Save dperussina/6e2f9d541e92f7335b0ad867ce41f146 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Importing required modules | |
const fs = require('fs'); | |
const readline = require('readline'); | |
const { google } = require('googleapis'); | |
var tools = require('tagnet-tools'); | |
// const { send } = require('process'); | |
const fetch = require('node-fetch'); | |
const path = require('path'); | |
const { JSDOM } = require("jsdom"); | |
// Define the scopes and token path | |
const SCOPES = ['https://www.googleapis.com/auth/gmail.modify']; | |
const TOKEN_PATH = '/DATA/apps/Catamaran_EmailAgent/src/token.json'; | |
// const TOKEN_PATH = 'token.json'; | |
const BASE_URL = 'https://services.agentgrid.net/Catamaran'; | |
// Function to preprocess data | |
async function preprocess() { | |
console.log('preprocess() Start '); | |
// Return a promise to handle asynchronous operations | |
return new Promise((resolve, reject) => { | |
var _sproc = 'EXEC SP_FindMissingProNumbers'; | |
// Execute SQL query using tagnet_queue function | |
tools.sql.tagnet_queue(_sproc, function (err, result) { | |
console.log('preprocess() End '); | |
// Handle errors | |
if (err) { | |
console.log('preprocess ERROR: ', _sproc, ' ', err, ' ', result); | |
resolve(err); | |
} else { | |
resolve(result); | |
} | |
}); | |
}); | |
} | |
async function main() { | |
// Load client secrets from a local file. | |
const credentialsPath = '/DATA/apps/Catamaran_EmailAgent/src/credentials.json'; | |
// const credentialsPath = 'credentials.json'; | |
fs.readFile(credentialsPath, (err, content) => { | |
if (err) return console.log('Error loading client secret file:', err); | |
// Authorize and then call the Gmail API. | |
authorize(JSON.parse(content), checkInbox); | |
}); | |
} | |
// Authorize with OAuth2 client | |
function authorize(credentials, callback) { | |
const { client_secret, client_id, redirect_uris } = credentials.web; | |
const oAuth2Client = new google.auth.OAuth2( | |
client_id, client_secret, redirect_uris[0]); | |
// Check if we have previously stored a token. | |
fs.readFile(TOKEN_PATH, (err, token) => { | |
if (err) return getNewToken(oAuth2Client, callback); | |
oAuth2Client.setCredentials(JSON.parse(token)); | |
callback(oAuth2Client); | |
}); | |
} | |
// Get and store new token after prompting for user authorization | |
function getNewToken(oAuth2Client, callback) { | |
const authUrl = oAuth2Client.generateAuthUrl({ | |
access_type: 'offline', | |
scope: SCOPES, | |
}); | |
console.log('Authorize this app by visiting this url:', authUrl); | |
const rl = readline.createInterface({ | |
input: process.stdin, | |
output: process.stdout, | |
}); | |
rl.question('Enter the code from that page here: ', (code) => { | |
rl.close(); | |
oAuth2Client.getToken(code, (err, token) => { | |
if (err) return console.error('Error retrieving access token', err); | |
oAuth2Client.setCredentials(token); | |
// Store the token to disk for later program executions | |
fs.writeFile(TOKEN_PATH, JSON.stringify(token), (err) => { | |
if (err) return console.error(err); | |
console.log('Token stored to', TOKEN_PATH); | |
}); | |
callback(oAuth2Client); | |
}); | |
}); | |
} | |
// Download and convert attachment to Base64 | |
async function downloadAndConvertToBase64(auth, messageId, part) { | |
const gmail = google.gmail({ version: 'v1', auth }); | |
try { | |
const response = await gmail.users.messages.attachments.get({ | |
userId: 'me', | |
messageId: messageId, | |
id: part.body.attachmentId | |
}); | |
// The data from the Gmail API is already in base64 but uses URL-safe characters. | |
// Convert it to standard base64 by replacing URL-safe characters. | |
const base64Data = response.data.data.replace(/-/g, '+').replace(/_/g, '/'); | |
return base64Data; | |
} catch (error) { | |
console.error('Error downloading or converting attachment:', error); | |
} | |
} | |
// Check Inbox for unread messages | |
function checkInbox(auth) { | |
const gmail = google.gmail({ version: 'v1', auth }); | |
gmail.users.messages.list({ | |
userId: 'me', | |
q: 'is:unread', | |
}, (err, res) => { | |
if (err) return console.log('The API returned an error: ' + err); | |
const messages = res.data.messages; | |
if (messages && messages.length) { | |
console.log('Messages: ', messages.length); | |
messages.forEach((message) => { | |
gmail.users.messages.get({ | |
userId: 'me', | |
id: message.id, | |
}, (err, res) => { | |
if (err) return console.log('The API returned an error: ' + err); | |
var _messageid = res.data.id; | |
// Extracting email headers | |
const getHeaderValue = (headerName) => { | |
const header = res.data.payload.headers.find(h => h.name === headerName); | |
return header ? header.value : null; | |
}; | |
var _existingConversation = {}; | |
// Extracting email details | |
var _to = getHeaderValue('To') || getHeaderValue('to') || getHeaderValue('To'); | |
var _cc = getHeaderValue('Cc') || getHeaderValue('cc') || getHeaderValue('CC'); // Extracting CC recipients | |
var _sender = getHeaderValue('Sender'); | |
var _for = getHeaderValue('for'); | |
if (_cc == null) { | |
_cc = _to; | |
} else { | |
_cc = _cc + ', ' + _to; | |
} | |
if (_sender != null) { | |
_to = _sender; | |
} | |
var _deliveredTo = getHeaderValue('Delivered-To'); | |
var _from = getHeaderValue('From'); | |
var _replyTo = getHeaderValue('Reply-To'); | |
console.log('To: ', _to, ' Sender:', _sender, '_deliveredTo : ', _deliveredTo, ' _replyTo: ', _replyTo, ' _for: ', _for, ' _from: ', _from, ' _cc: ', _cc, ' MessageID: ', _messageid); | |
// console.log(_from, ' ', _replyTo); | |
if (_to == null && _deliveredTo != null) { | |
_to = _deliveredTo; | |
} | |
if (_replyTo != null) { | |
if ((_from && !_from.includes('fragilepak.com') && !_from.includes('agentgrid.net')) || (_replyTo.includes('fragilepak.com') || _replyTo.includes('agentgrid.net'))) { | |
_from = _replyTo; | |
} | |
_cc = _cc + ', ' + _replyTo; | |
} | |
// console.log('CC: ', _cc); | |
var _subject = getHeaderValue('Subject'); | |
var _threadid = res.data.threadId; | |
var _body = ''; | |
var _direction = 'Inbound'; | |
var _numattachements = 0; | |
var isHtml = false; | |
// console.log('$$$ Before Body Search ') | |
if (res.data.payload.parts && res.data.payload.parts.length > 0) { | |
// console.log('$$ Starting Body Search') | |
const htmlPart = res.data.payload.parts.find(part => part.mimeType === 'text/html'); | |
if (htmlPart && htmlPart.body.data) { | |
_body = Buffer.from(htmlPart.body.data, 'base64').toString('utf-8'); | |
isHtml = true; | |
console.log('****: FOUND HTML'); | |
} else { | |
console.log('### Trying Alt Method ', res.data.payload.parts) | |
const textPart = res.data.payload.parts.find(part => part.mimeType === 'text/plain'); | |
if (textPart && textPart.body.data) { | |
_body = Buffer.from(textPart.body.data, 'base64').toString('utf-8'); | |
// isHtml remains false | |
console.log('****: FOUND TEXT'); | |
} else { | |
// _body = Buffer.from(res.data.payload.parts[0].body.data, 'base64').toString('utf-8'); | |
// _body = Buffer.from(res.data.payload.parts[0].body.data, 'base64').toString('utf-8'); | |
try { | |
_body = Buffer.from(res.data.payload.parts[0].body.data, 'base64').toString('utf-8'); | |
console.log('Trying Old Method ', _subject) | |
} catch (err) { | |
console.log('1 ****: Error Old Method: ', err, ' '); | |
} | |
if (_body == '') { | |
console.log('Trying Nested Method ', _subject) | |
try { | |
_body = Buffer.from(res.data.payload.parts[0].parts[0].body.data, 'base64').toString('utf-8'); | |
} catch (err) { | |
console.log('2 ****: Error: ', err, ' '); | |
} | |
} | |
function findBodyData(parts) { | |
for (const part of parts) { | |
if (part.body && part.body.data) { | |
return part.body.data; | |
} | |
if (part.parts) { | |
const foundData = findBodyData(part.parts); | |
if (foundData) { | |
return foundData; | |
} | |
} | |
} | |
return null; | |
} | |
if (_body == '') { | |
console.log('Trying THIS IS MY LAST RESORT Method ', _subject, ' MessageID: ', _messageid); | |
const bodyData = findBodyData(res.data.payload.parts); | |
if (bodyData) { | |
_body = Buffer.from(bodyData, 'base64').toString('utf-8'); | |
} else { | |
console.log('Could not find body data'); | |
} | |
} | |
} | |
} | |
// Once you have _body and isHtml, call formatEmailBody to format the content. | |
if (_to == '[email protected]') { | |
_body = extractInformation(_body) | |
} else { | |
_body = formatEmailBody(_body, isHtml); | |
} | |
// _body = Buffer.from(res.data.payload.parts[0].body.data, 'base64').toString('utf-8'); | |
// } | |
} else { | |
console.log('$$$ Alt Before Body Search ') | |
try { | |
_body = Buffer.from(res.data.payload.body.data, 'base64').toString('utf-8'); | |
} catch (err) { | |
console.log('****: Error: ', err, ' '); | |
} | |
if (_to == '[email protected]') { | |
_body = extractInformation(_body) | |
} else { | |
_body = formatEmailBody(_body, isHtml); | |
} | |
} | |
// Parsing _to variable to find catamaran.messages with a + sign | |
const regex = /catamaran\.messages\+(.*?)@/; | |
// console.log('^^^ _to: ', _to) | |
_to = extractEmails(_to); | |
if (_to) { | |
try { | |
const match = _to.match(regex); | |
if (match) { | |
if (_existingConversation === null) { | |
// Handle the case where _existingConversation is null | |
// For example, initializing it or logging an error | |
_existingConversation = { conversation: null }; // or any appropriate default value | |
} | |
console.log('^^^ match: ', match) | |
_existingConversation.conversation = match[1]; | |
} | |
} catch (err) { | |
console.log('****: Error: ', err, ' '); | |
} | |
} | |
try { | |
if (_replyTo) { | |
_replyTo = extractEmails(_replyTo); | |
console.log('About to test _replyTo ', _replyTo) | |
if (_existingConversation === null) { | |
// Handle the case where _existingConversation is null | |
// For example, initializing it or logging an error | |
_existingConversation = { conversation: null }; // or any appropriate default value | |
} | |
const match1 = _replyTo.match(regex); | |
if (match1) { | |
console.log('^^^ match: ', match1) | |
_existingConversation.conversation = match1[1]; | |
} | |
} | |
} catch (err) { | |
console.error('****: _replyTo Error: ', err, ' '); | |
} | |
try { | |
if (_cc && _cc != null) { | |
_cc = extractEmails(_cc); | |
console.log('About to test _cc ', _cc) | |
if (_existingConversation === null) { | |
// Handle the case where _existingConversation is null | |
// For example, initializing it or logging an error | |
_existingConversation = { conversation: null }; // or any appropriate default value | |
} | |
const match2 = _cc.match(regex); | |
if (match2) { | |
console.log('^^^ match: ', match2) | |
_existingConversation.conversation = match2[1]; | |
} | |
} | |
} catch (err) { | |
console.log('****: _cc Error: ', err, ' '); | |
} | |
// return; | |
// Checking for attachments | |
if (res.data.payload.parts) { | |
const attachments = res.data.payload.parts.filter(part => part.filename && part.filename.length > 0); | |
_numattachements = attachments.length; | |
// console.log(`Number of attachments: ${_numattachements}`); | |
attachments.forEach(async (attachmentPart) => { | |
const base64Data = await downloadAndConvertToBase64(auth, res.data.id, attachmentPart); | |
// console.log(`Attachment (filename: ${attachmentPart.filename}) in base64 length:`, base64Data.length); | |
const fileExtension = path.extname(attachmentPart.filename); | |
var _sproc = "EXEC catamaran.SP_InsertEmailAttachmentQueue @Base64 ='" + base64Data + "', " | |
_sproc += "@MessageID ='" + _messageid + "', " | |
if (_existingConversation && _existingConversation.conversation != null && _existingConversation.conversation.length > 0) { | |
_sproc += "@CatamaranConversationID ='" + _existingConversation.conversation + "', " | |
} else { | |
_sproc += "@CatamaranConversationID ='', " | |
} | |
_sproc += "@FileName ='" + attachmentPart.filename + "', " | |
_sproc += "@FileType ='" + fileExtension + "' " | |
tools.sql.tagnet_queue(_sproc, function (err, result) { | |
if (err) { | |
console.log('catamaran.SP_InsertEmailAttachmentQueue ERROR: ', _sproc, ' ', err, ' ', result); | |
} | |
const filePath = path.join(__dirname, 'queue', attachmentPart.filename); | |
// console.log(`Attachment (filename: ${attachmentPart.filename}) in base64 length:`, base64Data.length); | |
try { | |
fs.writeFileSync(filePath, base64Data, 'base64'); | |
} catch (err) { | |
console.error('Error writing file:', err); | |
} | |
}); | |
}); | |
} | |
// extractGroups(_messageid, extractEmails(_to), extractEmails(_cc)); | |
if (_body == '') { | |
console.log('!!! Missing body: , ', _subject) | |
} else { | |
if (_existingConversation.conversation && _existingConversation.conversation != null && _existingConversation.conversation.length > 0) { | |
} else { | |
_existingConversation = extractURLParams(_body); | |
} | |
} | |
// Preparing SQL procedure call | |
var _sproc = "EXEC catamaran.InsertIntoEmailQueue @To ='" + extractEmails(_to) + "', " | |
_sproc += "@From ='" + extractEmail(_from || "") + "', " | |
_sproc += "@CC ='" + (extractEmails(_cc) == null ? '' : extractEmails(_cc)) + "', " | |
_sproc += "@Subject ='" + (_subject || "").replace(/'/g, '"') + "', " | |
_sproc += "@Body ='" + (_body || "").replace(/'/g, '"') + "', " | |
_sproc += "@MessageID ='" + (_messageid || "") + "', " | |
_sproc += "@ThreadID ='" + (_threadid || "") + "', " | |
_sproc += "@ProNumber ='', " | |
_sproc += "@Direction ='" + (_direction || "") + "', " | |
_sproc += "@NumAttachements ='" + (_numattachements || "") + "'"; | |
if (_existingConversation && _existingConversation.conversation != null && _existingConversation.conversation.length > 0) { | |
_sproc += ", @ExistingCatarmaranConversationID ='" + _existingConversation.conversation + "' " | |
} | |
// console.log(_sproc); | |
// Calling SQL procedure | |
if (_body == '') { | |
// console.log('!!! Missing body: , ', _subject, ' ', _body) | |
// markMessageUnread(_messageid, auth); | |
// return; | |
_body = 'No Message Body'; | |
} | |
tools.sql.tagnet_queue(_sproc, function (err, result) { | |
if (err) { | |
console.log('catamaran.InsertIntoEmailQueue ERROR: ', _sproc, ' ', err, ' ', result); | |
} else { | |
markAndArchiveGmailMessage(_messageid, auth); | |
} | |
}); | |
}); | |
}); | |
} else { | |
console.log('No new messages.'); | |
// resolve(); | |
} | |
}); | |
// postPendingMessages(); | |
} | |
// Function to post pending messages | |
async function postPendingMessages() { | |
console.log('postPendingMessages() Start '); | |
var _records = []; | |
const _sproc = "EXEC [catamaran].[SP_GetEmailsPendingTransfer]"; | |
// Retrieve pending emails from the database | |
tools.sql.tagnet_queue(_sproc, function (err, result) { | |
// console.log('postPendingMessages() SQL: ', _sproc, ' ', result, err); | |
if (err) { | |
console.log('catamaran.SP_GetEmailsPendingTransfer ERROR: ', _sproc, ' ', err, ' ', result); | |
} | |
// console.log('postPendingMessages() result: ', result, ' Length: ', result.length); | |
_records = result; | |
// Process each pending email | |
tools.flow.queue_task(_records, function (data) { | |
return function (next) { | |
// console.log('postPendingMessages() Working: ', _records); | |
var _conversationID = ""; | |
// Check if the email has an existing conversation ID | |
if (data.CatarmaranConversationID == null) { | |
// New Conversation | |
if (data.CC != '') { | |
data.To = data.To + ', ' + data.CC; | |
} | |
createConversation({ | |
conversationType: 1, // Type of conversation (1 for new conversation) | |
// 1 = Normal (single pro), 2 = linked (more than one pro) | |
subject: data.Subject, | |
proNumbers: data.ProNumber, | |
emails: data.To, | |
message: data.Body, | |
isUrgent: false, | |
status: data.ProNumber.includes(',') ? 2 : 1, // Set status based on presence of commas // 0 = N/A, 1 = New, 2 = Open, 3 = Pending, 4 = Closed | |
userEmail: data.From, | |
isMaster: false, | |
masterPro: null, | |
id: data.id, | |
source: 'emailBot' | |
}, function (err, result) { | |
if (err) { | |
console.log('createConversation ERROR: ', err, ' ', result); | |
} else { | |
console.log('createConversation success, marking sent: ', result, ' ', data.id); | |
// [catamaran].[SP_SetEmailQueueSent] | |
tools.sql.tagnet_queue("EXEC [catamaran].[SP_SetEmailQueueSent] @id ='" + data.id + "'", function (err, result) { | |
if (err) { | |
console.log('catamaran.SP_SetEmailQueueSent ERROR: ', err, ' ', result, ' ', data.id); | |
} | |
}); | |
} | |
_conversationID = result; | |
// Check if the email has attachments | |
if (data.NumAttachements > 0) { | |
// Retrieve attachments for the email from the database | |
tools.sql.tagnet_queue("EXEC [catamaran].[SP_GetEmailAttachmentsByMessageIDPendingTransfer] @MessageID ='" + data.MessageID + "'", function (err, result) { | |
if (err) { | |
console.log('catamaran.SP_GetEmailAttachmentsByMessageIDPendingTransfer ERROR: ', err, ' ', result); | |
} | |
tools.flow.queue_task(result, function (attachment) { | |
return function (nextAttachment) { | |
// Insert each attachment into the conversation | |
// Read the file from the file system | |
fs.readFile('/DATA/apps/Catamaran_EmailAgent/src/queue/' + attachment.FileName, 'base64', function (err, data) { | |
// fs.readFile('./queue/' + attachment.FileName, 'base64', function (err, data) { | |
if (err) { | |
console.error('Error reading file:', err); | |
nextAttachment(); | |
return; | |
} | |
// Store the base64 data in the attachment.Base64FileData variable | |
attachment.Base64FileData = data; | |
// Insert the attachment into the conversation | |
insertAttachmentByConversationId({ | |
conversationId: parseInt(_conversationID), | |
userEmail: data.From, | |
// documentId: attachment.FileName, //TODO: Needs to be GUID | |
documentName: attachment.FileName, | |
// documentType: attachment.DocumentType, | |
text: 'Email Attachement', | |
fileType: attachment.FileType, | |
fileBase64String: attachment.Base64FileData, | |
partnerPrimaryOrderID: data.ProNumber, | |
source: 'emailBot' | |
}, function (err, result) { | |
if (err) { | |
console.error('insertAttachmentByConversationId ERROR: ', err, ' ', result); | |
nextAttachment(); | |
return; | |
} | |
tools.sql.tagnet_queue("EXEC [catamaran].[SP_SetEmailAttachmentQueueSent] @id ='" + attachment.id + "'", function (err, result) { | |
if (err) { | |
console.log('catamaran.SP_SetEmailAttachmentQueueSent ERROR: ', err, ' ', result, ' ', data.id); | |
nextAttachment(); | |
return; | |
} | |
nextAttachment(); | |
// Delete the file from the file system | |
fs.unlink('/DATA/apps/Catamaran_EmailAgent/src/queue/' + attachment.FileName, function (err) { | |
// fs.unlink('./queue/' + attachment.FileName, function (err) { | |
if (err) { | |
console.error('Error deleting file:', err); | |
} else { | |
console.log('File deleted successfully', attachment.FileName); | |
} | |
}); | |
}) | |
}); | |
}); | |
} | |
}, function (err, result) { | |
console.log('postPendingMessages() result: ', result); | |
}); | |
}); | |
} | |
next(); | |
}); | |
} else { | |
// Existing Conversation | |
_conversationID = data.CatarmaranConversationID; | |
// Insert the email message into the existing conversation | |
insertConversationMessage({ conversationId: data.CatarmaranConversationID, message: data.Body, messageBy: data.From, source: 'emailBot' }, function (err, result) { | |
if (err) { | |
console.log('createConversation ERROR: ', err, ' ', result); | |
} else { | |
console.log('createConversation success, marking sent: ', result, ' ', data.id); | |
// [catamaran].[SP_SetEmailQueueSent] | |
tools.sql.tagnet_queue("EXEC [catamaran].[SP_SetEmailQueueSent] @id ='" + data.id + "'", function (err, result) { | |
if (err) { | |
console.log('catamaran.SP_SetEmailQueueSent ERROR: ', err, ' ', result, ' ', data.id); | |
} | |
}); | |
if (data.CC != '') { | |
data.To = data.To + ', ' + data.CC; | |
} | |
var _payload = { | |
conversationId: data.CatarmaranConversationID // conversation id | |
, email: data.To //to and cc | |
, userEmail: data.From // from | |
, source: 'emailBot' // source | |
}; | |
InsertEmailByConversationId(_payload, function (err, reply) { | |
if (err) { | |
console.log('InsertEmailByConversationId ERROR: ', err, ' ', reply, ' ', _payload); | |
} else { | |
console.log('InsertEmailByConversationId success: ', _payload.conversationId) | |
} | |
}); | |
} | |
}); | |
// Check if the email has attachments | |
if (data.NumAttachements > 0) { | |
// Retrieve attachments for the email from the database | |
tools.sql.tagnet_queue("EXEC [catamaran].[SP_GetEmailAttachmentsByMessageIDPendingTransfer] @MessageID ='" + data.MessageID + "'", function (err, result) { | |
if (err) { | |
console.log('catamaran.SP_GetEmailAttachmentsByMessageIDPendingTransfer ERROR: ', err, ' ', result); | |
} | |
tools.flow.queue_task(result, function (attachment) { | |
return function (nextAttachment) { | |
// Insert each attachment into the conversation | |
// Read the file from the file system | |
fs.readFile('/DATA/apps/Catamaran_EmailAgent/src/queue/' + attachment.FileName, 'base64', function (err, data) { | |
// fs.readFile('./queue/' + attachment.FileName, 'base64', function (err, data) { | |
if (err) { | |
console.error('Error reading file:', err); | |
nextAttachment(); | |
return; | |
} | |
// Store the base64 data in the attachment.Base64FileData variable | |
attachment.Base64FileData = data; | |
// console.log('insertAttachmentByConversationId: file: ', attachment.FileName, ' ', attachment.Base64FileData.length, ' data: ', attachment.Base64FileData); | |
// Insert the attachment into the conversation | |
insertAttachmentByConversationId({ | |
conversationId: parseInt(_conversationID), | |
userEmail: data.From, | |
// documentId: attachment.FileName, //TODO: Needs to be GUID | |
documentName: attachment.FileName, | |
// documentType: attachment.DocumentType, | |
text: 'Email Attachement', | |
fileType: attachment.FileType, | |
fileBase64String: attachment.Base64FileData, | |
partnerPrimaryOrderID: data.ProNumber, | |
source: 'emailBot' | |
}, function (err, result) { | |
console.log('insertAttachmentByConversationId: ', _conversationID, ' Done. Error: ', err); | |
if (err) { | |
console.error('insertAttachmentByConversationId ERROR: ', err, ' ', result); | |
nextAttachment(); | |
return; | |
} | |
tools.sql.tagnet_queue("EXEC [catamaran].[SP_SetEmailAttachmentQueueSent] @id ='" + attachment.id + "'", function (err, result) { | |
if (err) { | |
console.log('catamaran.SP_SetEmailAttachmentQueueSent ERROR: ', err, ' ', result, ' ', data.id); | |
nextAttachment(); | |
return; | |
} | |
nextAttachment(); | |
// Delete the file from the file system | |
fs.unlink('/DATA/apps/Catamaran_EmailAgent/src/queue/' + attachment.FileName, function (err) { | |
// fs.unlink('./queue/' + attachment.FileName, function (err) { | |
if (err) { | |
console.error('Error deleting file:', err); | |
} else { | |
console.log('File deleted successfully', attachment.FileName); | |
} | |
}); | |
}) | |
}); | |
}); | |
} | |
}, function (err, result) { | |
console.log('postPendingMessages() result: ', result); | |
}); | |
}); | |
} | |
next(); | |
} | |
}; | |
}, function (err, result) { | |
console.log('postPendingMessages(): ', result); | |
}); | |
}); | |
} | |
// postPendingMessages(); | |
// Extract email from input string | |
function extractEmail(input) { | |
// This regular expression matches a pattern enclosed in angle brackets (< >). | |
const match = input.match(/<([^>]+)>/); | |
return match ? match[1] : input; | |
} | |
// Extract multiple emails from input string | |
function extractEmails(input) { | |
// Regular expression to match email addresses in the format of "[email protected]" or "<[email protected]>" | |
const regex = /([a-zA-Z0-9._+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,6})|<([a-zA-Z0-9._+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,6})>/g; | |
let match; | |
const emails = []; | |
while ((match = regex.exec(input)) !== null) { | |
// The email can be in either the first or second capturing group, depending on whether it was enclosed in angle brackets | |
const email = match[1] || match[2]; | |
if (!emails.includes(email)) { | |
emails.push(email); | |
} | |
} | |
return emails.length ? emails.join(', ') : null; | |
} | |
// Create a conversation | |
function createConversation(conversationData, callback) { | |
// Make a POST request to the API endpoint | |
console.log('createConversation: ', conversationData); | |
fetch(BASE_URL + '/api/TicketConversation/CreateConversation', { | |
method: 'POST', | |
headers: { | |
'Content-Type': 'application/json', | |
}, | |
body: JSON.stringify(conversationData), | |
}) | |
.then((response) => response.text()) // Get the raw body of the response | |
.then((data) => { | |
// Handle the response data | |
console.log('createConversation: ', data); | |
tools.sql.tagnet_queue("EXEC catamaran.SP_SetConverationID_ByID @id ='" + conversationData.id + "', @ConversationID = '" + data + "';", function (err, result) { | |
console.log('writing conversation id to email queue: ', err, ' ', result); | |
}); | |
callback(false, data); | |
}) | |
.catch((error) => { | |
// Handle any errors | |
console.error('createConversation ERROR: ', error); | |
callback(true, error); | |
}); | |
} | |
// Insert a conversation message | |
function insertConversationMessage(conversationMessage, callback) { | |
console.log('insertConversationMessage: ', conversationMessage); | |
// Make a POST request to the API endpoint | |
fetch(BASE_URL + '/api/TicketConversation/InsertConversationMessage', { | |
method: 'POST', | |
headers: { | |
'Content-Type': 'application/json', | |
}, | |
body: JSON.stringify(conversationMessage), | |
}) | |
.then((response) => response) | |
.then((data) => { | |
// Handle the response data | |
console.log('insertConversationMessage: ', data); | |
callback(false, data); | |
}) | |
.catch((error) => { | |
// Handle any errors | |
console.error('insertConversationMessage ERROR: ', error); | |
callback(true, error); | |
}); | |
} | |
// Insert emails to a conversation | |
function InsertEmailByConversationId(conversationMessage, callback) { | |
console.log('InsertEmailByConversationId: ', conversationMessage); | |
// Make a POST request to the API endpoint | |
fetch(BASE_URL + '/api/TicketConversation/InsertEmailByConversationId', { | |
method: 'POST', | |
headers: { | |
'Content-Type': 'application/json', | |
}, | |
body: JSON.stringify(conversationMessage), | |
}) | |
.then((response) => response) | |
.then((data) => { | |
// Handle the response data | |
console.log('InsertEmailByConversationId: ', data); | |
callback(false, data); | |
}) | |
.catch((error) => { | |
// Handle any errors | |
console.error('InsertEmailByConversationId ERROR: ', error); | |
callback(true, error); | |
}); | |
} | |
// Insert an attachment by conversation ID | |
function insertAttachmentByConversationId(attachmentData, callback) { | |
// Make a POST request to the API endpoint | |
// console.log('insertAttachmentByConversationId: ', attachmentData.fileBase64String, ' ', attachmentData.fileBase64String.length); | |
attachmentData.fileBase64String.length; | |
fetch(BASE_URL + '/api/TicketConversation/UploadFileAttachment', { | |
method: 'POST', | |
headers: { | |
'Content-Type': 'application/json', | |
}, | |
body: JSON.stringify(attachmentData), | |
}) | |
.then((response) => response.json()) | |
.then((data) => { | |
// Handle the response data | |
console.log('insertAttachmentByConversationId: ', data); | |
callback(false, data); | |
}) | |
.catch((error) => { | |
// Handle any errors | |
console.error('insertAttachmentByConversationId ERROR: ', error); | |
callback(true, error); | |
}); | |
} | |
// Function to extract URL parameters from a base64 encoded URL | |
function extractURLParams(url) { | |
try { | |
// Decode the URL | |
const decodedUrl = Buffer.from(url, 'base64').toString('utf-8'); | |
// Regular expression to extract the parameters | |
const regex = /pro=(\w+)&conversation=(\d+)/; | |
// Match the regex against the decoded URL | |
const match = decodedUrl.match(regex); | |
console.log('### extractURLParams(url)'); | |
// If there is a match, extract the parameters and return them | |
if (match) { | |
const pro = match[1]; | |
const conversation = match[2]; | |
console.log('### pro, conversation: ', pro, conversation); | |
return { pro, conversation }; | |
} | |
// If there is no match, return null | |
return null; | |
} catch (err) { | |
console.error('extractURLParams Avoided error: ', err); | |
return null; | |
} | |
} | |
// Function to execute the script | |
async function executeScript() { | |
console.log('##### executeScript() Start #####'); | |
try { | |
await preprocess(); // Preprocess the data | |
await main(); // Load client secrets and authorize | |
await preprocess(); // Preprocess the data again | |
await postPendingMessages(); // Post pending messages | |
} catch (error) { | |
console.error('Error executing script:', error); | |
} | |
setTimeout(executeScript, 30000); // Schedule the next execution after 30 seconds | |
} | |
// Create a queue to govern the speed of API calls | |
const apiQueue = []; | |
let isProcessingQueue = false; | |
// Function to enqueue a task in the API queue | |
function enqueueTask(task) { | |
apiQueue.push(task); | |
if (!isProcessingQueue) { | |
processQueue(); | |
} | |
} | |
// Function to process the API queue | |
async function processQueue() { | |
isProcessingQueue = true; | |
while (apiQueue.length > 0) { | |
const task = apiQueue.shift(); | |
try { | |
await task(); | |
} catch (error) { | |
console.error('Error processing task:', error); | |
} | |
} | |
isProcessingQueue = false; | |
} | |
// Function to mark and archive a Gmail message | |
function markAndArchiveGmailMessage(messageId, auth) { | |
// Add the task to the queue | |
console.log('markAndArchiveGmailMessage(messageId): ', messageId); | |
enqueueTask(async () => { | |
console.log('in apiQueue markAndArchiveGmailMessage(messageId): ', messageId); | |
try { | |
// await markGmailMessageAsRead(messageId, auth); // Mark the message as read | |
// await archiveGmailMessage(messageId, auth); // Archive the message | |
await deleteGmailMessageById(messageId, auth); // Delete the message | |
} catch (error) { | |
console.error('Error marking and archiving Gmail message:', error); | |
} | |
}); | |
} | |
// Function to mark and archive a Gmail message | |
function markMessageUnread(messageId, auth) { | |
// Add the task to the queue | |
console.log('markMessageUnread(messageId): ', messageId); | |
enqueueTask(async () => { | |
console.log('in apiQueue markMessageUnread(messageId): ', messageId); | |
try { | |
await markGmailMessageAsUnRead(messageId, auth); // Mark the message as read | |
} catch (error) { | |
console.error('Error marking unread Gmail message:', error); | |
} | |
}); | |
} | |
// Function to mark a Gmail message as unread | |
function markGmailMessageAsUnRead(messageId, auth) { | |
console.log('markGmailMessageAsUnRead(messageId): ', messageId); | |
const gmail = google.gmail({ version: 'v1', auth }); | |
return new Promise((resolve, reject) => { | |
gmail.users.messages.modify( | |
{ | |
userId: 'me', | |
id: messageId, | |
resource: { | |
addLabelIds: ['UNREAD'], // add the 'UNREAD' label to mark the message as read | |
}, | |
}, | |
(err, res) => { | |
if (err) { | |
console.error('Error marking Gmail message as unread:', err); | |
reject(err); | |
} else { | |
console.log('Gmail message marked as unread successfully'); | |
resolve(); | |
} | |
} | |
); | |
}); | |
} | |
// Function to mark a Gmail message as Trash | |
function deleteGmailMessageById(messageId, auth) { | |
// Your code to trash the Gmail message goes here | |
// You can use the Gmail API to modify the message's label | |
// Here's an example using the googleapis library: | |
console.log('archiveGmailMessage(messageId): ', messageId); | |
const gmail = google.gmail({ version: 'v1', auth }); | |
return new Promise((resolve, reject) => { | |
gmail.users.messages.trash({ | |
userId: 'me', | |
id: messageId, | |
}, (err, res) => { | |
if (err) { | |
console.error('Error deleting Gmail message:', err); | |
// Handle the error | |
reject(err); | |
} else { | |
console.log('Gmail message deleted successfully'); | |
// Handle the success | |
resolve(); | |
} | |
}); | |
}); | |
} | |
function formatEmailBody(body, isHtml = false) { | |
// Define the labels of the information to be extracted | |
// const labels = [ | |
// "Type of Inquiry", | |
// "Name", | |
// "Email", | |
// "Phone Number", | |
// "PRO Number", | |
// "Message" | |
// ]; | |
// const containsText = body.includes('Adjusts the display of header images based on the user"s preference for dark color schemes.'); | |
// Object to store the extracted information | |
let extractedInfo = {}; | |
if (isHtml) { | |
// Create a DOM from the HTML body | |
const dom = new JSDOM(body); | |
const document = dom.window.document; | |
// Replace all occurrences of two spaces with a single space | |
const htmlString = document.documentElement.outerHTML.replace(/style="[^"]*"/g, '').replace(/ {2}/g, ' ').replace(/<style\b[^<]*(?:(?!<\/style>)<[^<]*)*<\/style>/gi, ''); | |
// Return the transformed HTML as a string | |
return htmlString; | |
} else { | |
// For plain text, perform simple transformations for readability | |
// Example: Convert email quotes to a more readable format | |
let formattedText = body.replace(/^>+/gm, " "); | |
// Replace multiple line breaks with a single one to clean up spacing | |
formattedText = formattedText.replace(/\n\s*\n/g, "<br>"); | |
formattedText = formattedText.replace(/\r\n/g, "<br>"); | |
// Additional formatting rules can be applied here | |
// Remove excess <br> tags in a row | |
formattedText = formattedText.replace(/<br\s*\/?>\s*(<br\s*\/?>\s*){2,}/g, "<br>"); | |
// return formattedText; | |
// Additional formatting rules can be applied here | |
return formattedText; | |
} | |
} | |
function convertExtractedInfoToString(info) { | |
// Convert each key-value pair into a string in the format "Key: Value" | |
const readableString = Object.entries(info) | |
.map(([key, value]) => `${key}: ${value}`) | |
.join('<br>'); // Join all strings with a newline character | |
return readableString; | |
} | |
function extractInformation(body) { | |
console.log(' %%%%%%%%%%%%%%% extractInformation(body): ', body); | |
const dom = new JSDOM(body); | |
const document = dom.window.document; | |
const labels = [ | |
"Type of Inquiry", | |
"Name", | |
"Email", | |
"Phone Number", | |
"PRO Number", | |
"Message" | |
]; | |
let extractedInfo = {}; | |
labels.forEach(label => { | |
// Locate the <strong> element that contains the label | |
const strongTag = Array.from(document.querySelectorAll('strong')).find(el => el.textContent.includes(label)); | |
// Assuming the corresponding value is in the next <td class="field-value"> | |
// Note: Depending on the actual HTML structure, you might need a different method to correctly locate the value. | |
let value = ''; | |
if (strongTag) { | |
// Directly navigating to the .field-value that is supposed to follow | |
const fieldValueElement = strongTag.closest('tr').nextElementSibling.querySelector('.field-value'); | |
if (fieldValueElement) { | |
value = fieldValueElement.textContent.trim(); | |
} else { | |
// If no direct .field-value found, fall back to the next element's text | |
const nextElement = strongTag.parentElement.nextElementSibling; | |
if (nextElement) { | |
value = nextElement.textContent.trim(); | |
} | |
} | |
} | |
extractedInfo[label] = value; | |
console.log(' %%%%%%%%%%%%%%% extractInformation(extractedInfo): ', extractedInfo); | |
}); | |
return convertExtractedInfoToString(extractedInfo); | |
} | |
executeScript(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment