import fs from 'fs'; import path from 'path'; import { formatDuration } from '../lib/util.js'; export function createPendingApprovalsJob({ jiraService, webexService, log }) { const { logger, logWarn, logError, logDebug } = log; function sendApprovalReminder(personEmail, approvals) { return new Promise(function (resolve, reject) { let msgText = 'You have the following pending approvals:\n'; for (const approval of approvals) { msgText += `- [${approval.key}](https://aeo.atlassian.net/servicedesk/customer/portal/135/${approval.key}): ${approval.summary} ${approval.duration}\n`; } msgText += '\nYou can find these in the [Requests Pending Approvals](https://aeo.atlassian.net/servicedesk/customer/user/approvals?page=1) portal. If you have any questions or experience issues, please submit a [support request](https://aeo.atlassian.net/servicedesk/customer/portals).'; logDebug('sendApprovalReminder', `Sending direct reminder to ${personEmail}:\n${msgText}`); webexService.sendWebexMessage({ toPersonEmail: personEmail, markdown: msgText, }) .then(result => resolve(result)) .catch(error => reject(error)); }); } function runPendingApprovals() { return jiraService.searchUnapprovedRequests() .then(async function (tickets) { if (!tickets || tickets.length === 0) { logger('runPendingApprovals', 'No pending approval tickets found.'); return; } const needApproval = {}; for (const ticket of tickets) { if (ticket.fields.customfield_10033) { for (const approvals of ticket.fields.customfield_10033) { if (approvals.approvers.length > 0 && approvals.finalDecision == 'pending') { for (const approver of approvals.approvers) { if (approver.approverDecision != 'approved' && new Date(approvals.createdDate.iso8601) < new Date(new Date() - (24 * 60 * 60 * 1000))) { if (!needApproval[approver.approver.emailAddress]) { needApproval[approver.approver.emailAddress] = []; } needApproval[approver.approver.emailAddress].push({ key: ticket.key, summary: ticket.fields.summary, reporter: ticket.fields.reporter.displayName, duration: formatDuration(approvals.createdDate.iso8601), }); } } } } } else { logWarn('runPendingApprovals', `No approvals setup in customfield_10033 for ${ticket.key}.`); } } for (const approver in needApproval) { await sendApprovalReminder(approver, needApproval[approver]) .then(() => logger('runPendingApprovals', `Sent reminder to ${approver}.`)) .catch(error => logError('runPendingApprovals', `Failed to send reminder to ${approver}`, error)); } }) .catch(error => logError('runPendingApprovals', 'Failed to run pending approvals job', error)); } return { runPendingApprovals }; } export async function cleanupOldLogs(log) { const { logger, logError } = log; const now = Date.now(); const directory = './logs'; const sevenDaysInMs = 7 * 24 * 60 * 60 * 1000; let files; try { files = await fs.promises.readdir(directory); } catch (error) { logError('cleanupOldLogs', `Failed to read log directory ${directory}`, error); return; } for (const file of files) { const filePath = path.join(directory, file); try { const stats = await fs.promises.stat(filePath); if (stats.isFile() && (now - stats.mtimeMs) > sevenDaysInMs) { await fs.promises.unlink(filePath); logger('cleanupOldLogs', `Deleted old log file: ${file}`); } } catch (error) { logError('cleanupOldLogs', `Failed to process log file ${file}`, error); } } }