246 lines
No EOL
7.1 KiB
JavaScript
246 lines
No EOL
7.1 KiB
JavaScript
//This is a service which will download data for the latest updated Mantis tickets and store them in the database.
|
|
//It will also download all the notes and attachments for each ticket.
|
|
|
|
import axios from 'axios';
|
|
|
|
import { getSetting } from '../utils/settings.js';
|
|
|
|
import prisma from '../database.js';
|
|
|
|
import { logger } from '../utils/logging.js';
|
|
|
|
export async function getMantisSettings()
|
|
{
|
|
const MANTIS_API_KEY = await getSetting('MANTIS_API_KEY');
|
|
const MANTIS_API_ENDPOINT = await getSetting('MANTIS_API_ENDPOINT');
|
|
|
|
if (!MANTIS_API_ENDPOINT || !MANTIS_API_KEY)
|
|
{
|
|
return {
|
|
url: null,
|
|
headers: null,
|
|
};
|
|
}
|
|
const headers = {
|
|
Authorization: `${MANTIS_API_KEY}`,
|
|
Accept: 'application/json',
|
|
'Content-Type': 'application/json',
|
|
};
|
|
|
|
return { url: MANTIS_API_ENDPOINT, headers };
|
|
}
|
|
|
|
export async function getLatestMantisTickets()
|
|
{
|
|
const { url, headers } = await getMantisSettings();
|
|
const ticketUrl = `${url}/issues?project_id=1&page_size=50&select=id,updated_at`;
|
|
try
|
|
{
|
|
const response = await axios.get(ticketUrl, { headers });
|
|
return response.data.issues;
|
|
}
|
|
catch (error)
|
|
{
|
|
logger.error('Error fetching tickets data:', error);
|
|
return [];
|
|
}
|
|
}
|
|
|
|
export async function getDataForMantisTicket(ticketId)
|
|
{
|
|
const { url, headers } = await getMantisSettings();
|
|
// Removed notes from select, as they are fetched separately with attachments
|
|
const ticketUrl = `${url}/issues/${ticketId}?select=id,summary,description,created_at,updated_at,reporter,status,severity,priority,notes`;
|
|
try
|
|
{
|
|
const response = await axios.get(ticketUrl, { headers });
|
|
// Assuming response.data contains the issue object directly
|
|
return response.data.issues && response.data.issues.length > 0 ? response.data.issues[0] : null;
|
|
}
|
|
catch (error)
|
|
{
|
|
logger.error(`Error fetching ticket data for ID ${ticketId}:`, error);
|
|
throw new Error(`Failed to fetch ticket data for ID ${ticketId} from Mantis.`);
|
|
}
|
|
}
|
|
|
|
export async function saveTicketToDatabase(ticketId)
|
|
{
|
|
const ticketData = await getDataForMantisTicket(ticketId);
|
|
|
|
if (!ticketData)
|
|
{
|
|
logger.warn(`No ticket data found for ID ${ticketId}. Skipping save.`);
|
|
return null;
|
|
}
|
|
|
|
const ticketInDb = await prisma.$transaction(async(tx) =>
|
|
{
|
|
const reporterUsername = ticketData.reporter?.name;
|
|
|
|
const ticket = await tx.mantisIssue.upsert({
|
|
where: { id: ticketId },
|
|
update: {
|
|
title: ticketData.summary,
|
|
description: ticketData.description,
|
|
reporterUsername,
|
|
status: ticketData.status.name,
|
|
priority: ticketData.priority.name,
|
|
severity: ticketData.severity.name,
|
|
updatedAt: new Date(ticketData.updated_at),
|
|
},
|
|
create: {
|
|
id: ticketId,
|
|
title: ticketData.summary,
|
|
description: ticketData.description,
|
|
reporterUsername,
|
|
status: ticketData.status.name,
|
|
priority: ticketData.priority.name,
|
|
severity: ticketData.severity.name,
|
|
createdAt: new Date(ticketData.created_at),
|
|
updatedAt: new Date(ticketData.updated_at),
|
|
},
|
|
});
|
|
logger.info(`Ticket ${ticketId} saved to database.`);
|
|
|
|
// Process notes
|
|
if (ticketData.notes && ticketData.notes.length > 0)
|
|
{
|
|
for (const note of ticketData.notes)
|
|
{
|
|
const noteReporter = note.reporter?.name || 'Unknown Reporter';
|
|
|
|
const comment = await tx.mantisComment.create({
|
|
data: {
|
|
mantisIssueId: ticketId,
|
|
senderUsername: noteReporter,
|
|
comment: note.text,
|
|
createdAt: new Date(note.created_at),
|
|
},
|
|
});
|
|
|
|
// Process attachments for the note
|
|
if (note.attachments && note.attachments.length > 0)
|
|
{
|
|
for (const attachment of note.attachments)
|
|
{
|
|
const attachmentData = {
|
|
commentId: comment.id,
|
|
filename: attachment.filename,
|
|
url: '/mantis/attachment/' + ticketId + '/' + attachment.id,
|
|
mimeType: attachment.content_type,
|
|
size: attachment.size,
|
|
uploadedAt: new Date(attachment.created_at),
|
|
};
|
|
|
|
await tx.mantisAttachment.create({
|
|
data: attachmentData,
|
|
});
|
|
logger.info(`Attachment ${attachment.filename} for ticket ${ticketId} saved to database.`);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return ticket;
|
|
});
|
|
|
|
return ticketInDb;
|
|
}
|
|
|
|
async function processNewMantisTickets()
|
|
{
|
|
logger.info('Checking for new Mantis tickets...');
|
|
const issues = await getLatestMantisTickets();
|
|
|
|
if (!issues)
|
|
{
|
|
logger.warn('No issues returned from getLatestMantisTickets.');
|
|
return;
|
|
}
|
|
|
|
//Check if the tickets exist, and if not, or if they have a newer updated_at date, add them to the download queue
|
|
for (const issue of issues)
|
|
{
|
|
const ticketId = issue.id;
|
|
const existingTicket = await prisma.mantisIssue.findUnique({ // Changed from prisma.ticket to prisma.mantisIssue
|
|
where: { id: ticketId },
|
|
select: { updatedAt: true } // Only select needed field
|
|
});
|
|
|
|
if (!existingTicket || new Date(issue.updated_at) > new Date(existingTicket.updatedAt)) // Changed existingTicket.updated_at to existingTicket.updatedAt
|
|
{
|
|
// Avoid adding duplicates to the queue
|
|
if (!downloadQueue.includes(ticketId))
|
|
{
|
|
downloadQueue.push(ticketId);
|
|
logger.info(`Queueing ticket ${ticketId} for processing.`);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
async function processTicketsInQueue()
|
|
{
|
|
if (downloadQueue.length === 0)
|
|
{
|
|
return;
|
|
}
|
|
logger.info(`Processing tickets in queue: ${downloadQueue.length} tickets remaining.`);
|
|
|
|
// const ticketId = downloadQueue.shift();
|
|
//Pick a random ticket from the queue
|
|
const randomIndex = Math.floor(Math.random() * downloadQueue.length);
|
|
const ticketId = downloadQueue[randomIndex];
|
|
downloadQueue.splice(randomIndex, 1);
|
|
try
|
|
{
|
|
logger.info(`Processing ticket ${ticketId}...`);
|
|
await saveTicketToDatabase(ticketId);
|
|
logger.info(`Ticket ${ticketId} processed and saved to database.`);
|
|
}
|
|
catch (error)
|
|
{
|
|
console.log(error);
|
|
logger.error(`Error processing ticket ${ticketId}:`, error);
|
|
// Optionally, you can re-add the ticket to the queue for retrying later
|
|
downloadQueue.push(ticketId);
|
|
}
|
|
}
|
|
|
|
const downloadQueue = [];
|
|
|
|
export async function setup()
|
|
{
|
|
try
|
|
{
|
|
// Initialize the download queue
|
|
downloadQueue.length = 0;
|
|
|
|
// Start the process of checking for new tickets
|
|
processNewMantisTickets();
|
|
setInterval(processNewMantisTickets, 5 * 60 * 1000); // Check for new tickets every 5 minutes
|
|
setInterval(processTicketsInQueue, 1 * 1000); // Process the queue every 10 seconds
|
|
|
|
if(process.env.LOAD_ALL_MANTISES == 'true')
|
|
{
|
|
for (let i = 3000; i <= 5100; i++)
|
|
{
|
|
//Check if the ticket already exists in the database
|
|
const existingTicket = await prisma.mantisIssue.findUnique({
|
|
where: { id: i },
|
|
select: { updatedAt: true } // Only select needed field
|
|
});
|
|
|
|
if (!existingTicket)
|
|
{
|
|
downloadQueue.push(i);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
catch(error)
|
|
{
|
|
logger.error('Error setting up Mantis downloader:', error);
|
|
}
|
|
} |