From 3fa370765e7b3af770ad9ec66b6381da154a067a Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Wed, 21 Jan 2026 09:52:31 -0800 Subject: [PATCH] purge papaparse --- server/package-lock.json | 7 -- server/package.json | 1 - server/src/config/services.ts | 2 - server/src/controllers/incidentController.ts | 1 + server/src/controllers/monitorController.ts | 22 +--- server/src/service/business/monitorService.ts | 107 +++++++----------- 6 files changed, 48 insertions(+), 92 deletions(-) diff --git a/server/package-lock.json b/server/package-lock.json index a1a392b18..2dd8d23e7 100644 --- a/server/package-lock.json +++ b/server/package-lock.json @@ -36,7 +36,6 @@ "mongoose": "^8.3.3", "multer": "^1.4.5-lts.1", "nodemailer": "^6.9.14", - "papaparse": "^5.5.2", "ping": "0.4.4", "sharp": "0.33.5", "ssl-checker": "2.0.10", @@ -11567,12 +11566,6 @@ "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==", "license": "BlueOak-1.0.0" }, - "node_modules/papaparse": { - "version": "5.5.3", - "resolved": "https://registry.npmjs.org/papaparse/-/papaparse-5.5.3.tgz", - "integrity": "sha512-5QvjGxYVjxO59MGU2lHVYpRWBBtKHnlIAcSe1uNFCkkptUh63NFRj0FJQm7nR67puEruUci/ZkjmEFrjCAyP4A==", - "license": "MIT" - }, "node_modules/parent-module": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", diff --git a/server/package.json b/server/package.json index 2bf898c94..2cbacea39 100755 --- a/server/package.json +++ b/server/package.json @@ -48,7 +48,6 @@ "mongoose": "^8.3.3", "multer": "^1.4.5-lts.1", "nodemailer": "^6.9.14", - "papaparse": "^5.5.2", "ping": "0.4.4", "sharp": "0.33.5", "ssl-checker": "2.0.10", diff --git a/server/src/config/services.ts b/server/src/config/services.ts index de4d5115f..423e23ca5 100644 --- a/server/src/config/services.ts +++ b/server/src/config/services.ts @@ -24,7 +24,6 @@ import InviteService from "../service/business/inviteService.js"; import MaintenanceWindowService from "../service/business/maintenanceWindowService.js"; import { MonitorService } from "@/service/index.js"; import IncidentService from "../service/business/incidentService.js"; -import papaparse from "papaparse"; import axios from "axios"; import got from "got"; import ping from "ping"; @@ -276,7 +275,6 @@ export const initializeServices = async ({ const monitorService = new MonitorService({ jobQueue: superSimpleQueue, emailService, - papaparse, logger, errorService, games, diff --git a/server/src/controllers/incidentController.ts b/server/src/controllers/incidentController.ts index 93783b20c..a5477e019 100644 --- a/server/src/controllers/incidentController.ts +++ b/server/src/controllers/incidentController.ts @@ -73,6 +73,7 @@ class IncidentController { resolveIncidentManually = async (req: Request, res: Response, next: NextFunction) => { try { + console.log({ user: req.user }); const resolvedIncident = await this.incidentService.resolveIncident( req?.params?.incidentId, req?.user?.id, diff --git a/server/src/controllers/monitorController.ts b/server/src/controllers/monitorController.ts index 2ebb113ae..30ceabbc5 100644 --- a/server/src/controllers/monitorController.ts +++ b/server/src/controllers/monitorController.ts @@ -174,27 +174,15 @@ class MonitorController { createBulkMonitors = async (req: Request, res: Response, next: NextFunction) => { try { - if (!req.file) { - throw new AppError({ message: "No file uploaded", status: 400 }); + const userId = req.user?.id; + if (!userId) { + throw new AppError({ message: "User ID is required", status: 400 }); } - if (!req.file.mimetype.includes("csv")) { - throw new AppError({ message: "File is not a CSV", status: 400 }); - } - - if (req.file.size === 0) { - throw new AppError({ message: "File is empty", status: 400 }); - } - - const userId = requireString(req?.user?.id, "User ID"); const teamId = requireTeamId(req?.user?.teamId); - const fileData = req?.file?.buffer?.toString("utf-8"); - if (!fileData) { - throw new AppError({ message: "Cannot get file from buffer", status: 400 }); - } - - const monitors = await this.monitorService.createBulkMonitors(fileData, userId, teamId); + const data = req.body; + const monitors = await this.monitorService.createBulkMonitors(data, userId, teamId); return res.status(200).json({ success: true, diff --git a/server/src/service/business/monitorService.ts b/server/src/service/business/monitorService.ts index 4972bdee7..4f97bdf0f 100644 --- a/server/src/service/business/monitorService.ts +++ b/server/src/service/business/monitorService.ts @@ -1,7 +1,13 @@ import { createMonitorsBodyValidation } from "@/validation/joi.js"; import { NormalizeData, NormalizeDataUptimeDetails } from "@/utils/dataUtils.js"; import { type Monitor } from "@/types/index.js"; -import type { MonitorType, MonitorsWithChecksByTeamIdResult, UptimeDetailsResult, HardwareDetailsResult, PageSpeedDetailsResult } from "@/types/monitor.js"; +import type { + MonitorType, + MonitorsWithChecksByTeamIdResult, + UptimeDetailsResult, + HardwareDetailsResult, + PageSpeedDetailsResult, +} from "@/types/monitor.js"; import type { IChecksRepository, IMonitorsRepository, IMonitorStatsRepository, IStatusPagesRepository } from "@/repositories/index.js"; import fs from "fs"; import { fileURLToPath } from "url"; @@ -18,7 +24,7 @@ export interface IMonitorService { // create createMonitor(teamId: string, userId: string, body: Monitor): Promise; - createBulkMonitors(fileData: string, userId: string, teamId: string): Promise; + createBulkMonitors(monitors: Array, userId: string, teamId: string): Promise; addDemoMonitors(args: { userId: string; teamId: string }): Promise; // read @@ -68,7 +74,6 @@ export class MonitorService implements IMonitorService { private jobQueue: ISuperSimpleQueue; private emailService: any; - private papaparse: any; private logger: any; private errorService: any; private games: any; @@ -80,7 +85,6 @@ export class MonitorService implements IMonitorService { constructor({ jobQueue, emailService, - papaparse, logger, errorService, games, @@ -91,7 +95,6 @@ export class MonitorService implements IMonitorService { }: { jobQueue: ISuperSimpleQueue; emailService: any; - papaparse: any; logger: any; errorService: any; games: any; @@ -102,7 +105,6 @@ export class MonitorService implements IMonitorService { }) { this.jobQueue = jobQueue; this.emailService = emailService; - this.papaparse = papaparse; this.logger = logger; this.errorService = errorService; this.games = games; @@ -150,63 +152,14 @@ export class MonitorService implements IMonitorService { this.jobQueue.addJob(monitor.id, monitor); }; - createBulkMonitors = async (fileData: string, userId: string, teamId: string): Promise => { - const { parse } = this.papaparse; + createBulkMonitors = async (monitors: Array, userId: string, teamId: string): Promise => { + const createdMonitors = await this.monitorsRepository.createBulkMonitors(monitors); + if (!monitors || monitors.length === 0) { + throw new AppError("Failed to create monitors", 500); + } - return new Promise((resolve, reject) => { - parse(fileData, { - header: true, - skipEmptyLines: true, - transform: (value: string, header: string): string | number | undefined => { - if (value === "") return undefined; // Empty fields become undefined - - // Handle 'port' and 'interval' fields, check if they're valid numbers - if (["port", "interval"].includes(header)) { - const num = parseInt(value, 10); - if (isNaN(num)) { - throw this.errorService.createBadRequestError(`${header} should be a valid number, got: ${value}`); - } - return num; - } - - return value; - }, - complete: async ({ data, errors }: { data: any[]; errors: Error[] }): Promise => { - try { - if (errors.length > 0) { - throw this.errorService.createServerError("Error parsing CSV"); - } - - if (!data || data.length === 0) { - throw this.errorService.createServerError("CSV file contains no data rows"); - } - - const enrichedData = data.map((monitor: Monitor) => ({ - ...monitor, - userId, - teamId, - description: monitor.description || monitor.name || monitor.url, - name: monitor.name || monitor.url, - type: monitor.type || "http", - })); - - await createMonitorsBodyValidation.validateAsync(enrichedData); - - const monitors = await this.monitorsRepository.createBulkMonitors(enrichedData); - - await Promise.all( - monitors.map(async (monitor: Monitor) => { - this.jobQueue.addJob(monitor.id, monitor); - }) - ); - - resolve(monitors); - } catch (error) { - reject(error); - } - }, - }); - }); + await Promise.all(createdMonitors.map((monitor) => this.jobQueue.addJob(monitor.id, monitor))); + return createdMonitors; }; addDemoMonitors = async ({ userId, teamId }: { userId: string; teamId: string }): Promise => { @@ -277,7 +230,15 @@ export class MonitorService implements IMonitorService { }; }; - getHardwareDetailsById = async ({ teamId, monitorId, dateRange }: { teamId: string; monitorId: string; dateRange: string }): Promise => { + getHardwareDetailsById = async ({ + teamId, + monitorId, + dateRange, + }: { + teamId: string; + monitorId: string; + dateRange: string; + }): Promise => { const monitor = await this.monitorsRepository.findById(monitorId, teamId); if (!monitor) { throw new AppError({ message: `Monitor with ID ${monitorId} not found.`, status: 404 }); @@ -308,7 +269,15 @@ export class MonitorService implements IMonitorService { }; }; - getPageSpeedDetailsById = async ({ teamId, monitorId, dateRange }: { teamId: string; monitorId: string; dateRange: string }): Promise => { + getPageSpeedDetailsById = async ({ + teamId, + monitorId, + dateRange, + }: { + teamId: string; + monitorId: string; + dateRange: string; + }): Promise => { const monitor = await this.monitorsRepository.findById(monitorId, teamId); if (!monitor) { throw new AppError({ message: `Monitor with ID ${monitorId} not found.`, status: 404 }); @@ -342,7 +311,15 @@ export class MonitorService implements IMonitorService { return monitor; }; - getMonitorsByTeamId = async ({ teamId, type, filter }: { teamId: string; type?: MonitorType | MonitorType[]; filter?: string }): Promise => { + getMonitorsByTeamId = async ({ + teamId, + type, + filter, + }: { + teamId: string; + type?: MonitorType | MonitorType[]; + filter?: string; + }): Promise => { const monitors = await this.monitorsRepository.findByTeamId(teamId, { type, filter,