diff --git a/client/src/Pages/Settings/index.tsx b/client/src/Pages/Settings/index.tsx index 679d66126..e51255157 100644 --- a/client/src/Pages/Settings/index.tsx +++ b/client/src/Pages/Settings/index.tsx @@ -262,15 +262,7 @@ export const SettingsPage = () => { if (value === undefined) { (acc as any)[typedKey] = ""; } else if (typeof value === "object" && value !== null) { - // Handle nested objects like globalThresholds - // Convert 0 to "" for unsetting thresholds - (acc as any)[typedKey] = Object.entries(value).reduce( - (nested, [nestedKey, nestedValue]) => ({ - ...nested, - [nestedKey]: nestedValue === undefined ? "" : nestedValue, - }), - {} - ); + (acc as any)[typedKey] = value; } else { (acc as any)[typedKey] = value; } diff --git a/server/src/controllers/settingsController.ts b/server/src/controllers/settingsController.ts index d3caa0d8f..0fd82a8ac 100644 --- a/server/src/controllers/settingsController.ts +++ b/server/src/controllers/settingsController.ts @@ -2,14 +2,15 @@ import { Request, Response, NextFunction } from "express"; import { updateAppSettingsBodyValidation } from "@/validation/settingsValidation.js"; import { sendTestEmailBodyValidation } from "@/validation/notificationValidation.js"; import { AppError } from "@/utils/AppError.js"; +import { IEmailService, ISettingsService } from "@/service/index.js"; const SERVICE_NAME = "SettingsController"; class SettingsController { static SERVICE_NAME = SERVICE_NAME; - private settingsService: any; - private emailService: any; - constructor(settingsService: any, emailService: any) { + private settingsService: ISettingsService; + private emailService: IEmailService; + constructor(settingsService: ISettingsService, emailService: IEmailService) { this.settingsService = settingsService; this.emailService = emailService; } @@ -57,9 +58,9 @@ class SettingsController { updateAppSettings = async (req: Request, res: Response, next: NextFunction) => { try { - updateAppSettingsBodyValidation.parse(req.body); + const validatedBody = updateAppSettingsBodyValidation.parse(req.body); - const updatedSettings = await this.settingsService.updateDbSettings(req.body); + const updatedSettings = await this.settingsService.updateDbSettings(validatedBody); const returnSettings = this.buildAppSettings(updatedSettings); return res.status(200).json({ success: true, @@ -95,6 +96,9 @@ class SettingsController { const context = { testName: "Monitoring System" }; const html = await this.emailService.buildEmail("testEmailTemplate", context); + if (!html) { + throw new AppError({ message: "Failed to build email template.", status: 500 }); + } const messageId = await this.emailService.sendEmail(to, subject, html, { systemEmailHost, systemEmailPort, diff --git a/server/src/service/system/settingsService.ts b/server/src/service/system/settingsService.ts index ac4dfc425..10ac61725 100755 --- a/server/src/service/system/settingsService.ts +++ b/server/src/service/system/settingsService.ts @@ -19,6 +19,7 @@ export interface ISettingsService { loadSettings(): EnvConfig; getSettings(): EnvConfig; getDBSettings(): Promise; + updateDbSettings(newSettings: Partial): Promise; } export class SettingsService implements ISettingsService { diff --git a/server/src/validation/settingsValidation.ts b/server/src/validation/settingsValidation.ts index e7f0dc9b4..b9551dd4e 100644 --- a/server/src/validation/settingsValidation.ts +++ b/server/src/validation/settingsValidation.ts @@ -7,17 +7,17 @@ import { z } from "zod"; export const updateAppSettingsBodyValidation = z .object({ - checkTTL: z.union([z.number().int().min(1).max(CHECK_TTL_SENTINEL), z.literal("")]).optional(), - systemEmailPort: z.union([z.number(), z.literal("")]).optional(), - pagespeedApiKey: z.union([z.string(), z.literal("")]).optional(), - language: z.union([z.string(), z.literal("")]).optional(), - timezone: z.union([z.string(), z.literal("")]).optional(), - systemEmailHost: z.union([z.string(), z.literal("")]).optional(), - systemEmailAddress: z.union([z.string(), z.literal("")]).optional(), - systemEmailPassword: z.union([z.string(), z.literal("")]).optional(), - systemEmailUser: z.union([z.string(), z.literal("")]).optional(), - systemEmailConnectionHost: z.union([z.string(), z.literal("")]).optional(), - systemEmailTLSServername: z.union([z.string(), z.literal("")]).optional(), + checkTTL: z.number().int().min(1).max(CHECK_TTL_SENTINEL).optional(), + systemEmailPort: z.number().optional(), + pagespeedApiKey: z.string().optional(), + language: z.string().optional(), + timezone: z.string().optional(), + systemEmailHost: z.string().optional(), + systemEmailAddress: z.string().optional(), + systemEmailPassword: z.string().optional(), + systemEmailUser: z.string().optional(), + systemEmailConnectionHost: z.string().optional(), + systemEmailTLSServername: z.string().optional(), showURL: z.boolean().optional(), systemEmailSecure: z.boolean().optional(), @@ -28,10 +28,10 @@ export const updateAppSettingsBodyValidation = z globalThresholds: z .object({ - cpu: z.union([z.number().min(1).max(100), z.literal("")]).optional(), - memory: z.union([z.number().min(1).max(100), z.literal("")]).optional(), - disk: z.union([z.number().min(1).max(100), z.literal("")]).optional(), - temperature: z.union([z.number().min(1).max(150), z.literal("")]).optional(), + cpu: z.number().min(1).max(100).optional(), + memory: z.number().min(1).max(100).optional(), + disk: z.number().min(1).max(100).optional(), + temperature: z.number().min(1).max(150).optional(), }) .optional(), })