mirror of
https://github.com/bluewave-labs/Checkmate.git
synced 2026-05-21 00:48:45 -05:00
Merge pull request #3238 from bluewave-labs/feat/v2-create-config-status-page
feat: v2 create config status page
This commit is contained in:
@@ -82,7 +82,15 @@ class StatusPageController {
|
||||
const showURL = settings.showURL;
|
||||
|
||||
const monitors = await this.monitorsRepository.findByIds(statusPage.monitors);
|
||||
const normalizedMonitors = monitors.map((monitor) => {
|
||||
// Sort monitors according to the order in statusPage.monitors
|
||||
const monitorOrder = new Map(statusPage.monitors.map((id, index) => [id, index]));
|
||||
const sortedMonitors = [...monitors].sort((a, b) => {
|
||||
const orderA = monitorOrder.get(a.id) ?? Number.MAX_SAFE_INTEGER;
|
||||
const orderB = monitorOrder.get(b.id) ?? Number.MAX_SAFE_INTEGER;
|
||||
return orderA - orderB;
|
||||
});
|
||||
|
||||
const normalizedMonitors = sortedMonitors.map((monitor) => {
|
||||
const normalizedChecks = NormalizeData(monitor.recentChecks, 10, 100);
|
||||
if (!showURL) {
|
||||
const { url, port, secret, notifications, ...rest } = monitor;
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
import { Schema, model, type Types } from "mongoose";
|
||||
import type { StatusPage, StatusPageLogo } from "@/types/statusPage.js";
|
||||
import type { StatusPage, StatusPageLogoDocument } from "@/types/statusPage.js";
|
||||
import { StatusPageTypes } from "@/types/statusPage.js";
|
||||
|
||||
type StatusPageDocumentBase = Omit<
|
||||
StatusPage,
|
||||
"id" | "userId" | "teamId" | "monitors" | "subMonitors" | "originalMonitors" | "createdAt" | "updatedAt"
|
||||
"id" | "userId" | "teamId" | "monitors" | "subMonitors" | "originalMonitors" | "logo" | "createdAt" | "updatedAt"
|
||||
> & {
|
||||
monitors: Types.ObjectId[];
|
||||
subMonitors: Types.ObjectId[];
|
||||
originalMonitors?: Types.ObjectId[];
|
||||
logo?: StatusPageLogo | null;
|
||||
logo?: StatusPageLogoDocument | null;
|
||||
};
|
||||
|
||||
interface StatusPageDocument extends StatusPageDocumentBase {
|
||||
@@ -20,7 +20,7 @@ interface StatusPageDocument extends StatusPageDocumentBase {
|
||||
updatedAt: Date;
|
||||
}
|
||||
|
||||
const logoSchema = new Schema<StatusPageLogo & { data: Buffer }>(
|
||||
const logoSchema = new Schema<StatusPageLogoDocument>(
|
||||
{
|
||||
data: { type: Buffer },
|
||||
contentType: { type: String },
|
||||
|
||||
@@ -1,9 +1,13 @@
|
||||
import { IStatusPagesRepository } from "@/repositories/index.js";
|
||||
import { type StatusPageDocument, StatusPageModel } from "@/db/models/StatusPage.js";
|
||||
import type { StatusPage, StatusPageLogo } from "@/types/statusPage.js";
|
||||
import type { StatusPage, StatusPageLogo, StatusPageLogoDocument } from "@/types/statusPage.js";
|
||||
import mongoose from "mongoose";
|
||||
import { AppError } from "@/utils/AppError.js";
|
||||
|
||||
// Type for update data that can include document-level fields (Buffer for logo)
|
||||
type StatusPageUpdateData = Partial<Omit<StatusPage, "id" | "userId" | "teamId" | "logo" | "createdAt" | "updatedAt">> & {
|
||||
logo?: StatusPageLogoDocument | null;
|
||||
};
|
||||
class MongoStatusPagesRepository implements IStatusPagesRepository {
|
||||
private toStringId = (value?: mongoose.Types.ObjectId | string | null): string => {
|
||||
if (!value) {
|
||||
@@ -23,12 +27,14 @@ class MongoStatusPagesRepository implements IStatusPagesRepository {
|
||||
return values?.map((value) => this.toStringId(value)) ?? [];
|
||||
};
|
||||
|
||||
private mapLogo = (logo?: StatusPageLogo | null): StatusPageLogo | undefined => {
|
||||
private mapLogo = (logo?: StatusPageLogoDocument | null): StatusPageLogo | undefined => {
|
||||
if (!logo) {
|
||||
return undefined;
|
||||
}
|
||||
// Convert Buffer to base64 string for JSON serialization
|
||||
const base64Data = Buffer.isBuffer(logo.data) ? logo.data.toString("base64") : logo.data;
|
||||
return {
|
||||
data: logo.data,
|
||||
data: base64Data,
|
||||
contentType: logo.contentType,
|
||||
};
|
||||
};
|
||||
@@ -65,14 +71,15 @@ class MongoStatusPagesRepository implements IStatusPagesRepository {
|
||||
};
|
||||
|
||||
create = async (userId: string, teamId: string, image: Express.Multer.File | undefined, data: Partial<StatusPage>): Promise<StatusPage> => {
|
||||
const { logo: _logo, ...restData } = data;
|
||||
const statusPage = new StatusPageModel({
|
||||
...data,
|
||||
...restData,
|
||||
userId,
|
||||
teamId,
|
||||
});
|
||||
if (image) {
|
||||
statusPage.logo = {
|
||||
data: image.buffer,
|
||||
data: image.buffer as Buffer,
|
||||
contentType: image.mimetype,
|
||||
};
|
||||
}
|
||||
@@ -96,17 +103,24 @@ class MongoStatusPagesRepository implements IStatusPagesRepository {
|
||||
return this.mapDocuments(statusPages);
|
||||
};
|
||||
|
||||
updateById = async (id: string, teamId: string, image: Express.Multer.File | undefined, patch: Partial<StatusPage>): Promise<StatusPage> => {
|
||||
updateById = async (
|
||||
id: string,
|
||||
teamId: string,
|
||||
image: Express.Multer.File | undefined,
|
||||
patch: Partial<StatusPage> & { removeLogo?: string }
|
||||
): Promise<StatusPage> => {
|
||||
const { logo: _logo, removeLogo, ...restPatch } = patch;
|
||||
const updateData: StatusPageUpdateData = { ...restPatch };
|
||||
if (image) {
|
||||
patch.logo = {
|
||||
data: image.buffer,
|
||||
updateData.logo = {
|
||||
data: image.buffer as Buffer,
|
||||
contentType: image.mimetype,
|
||||
};
|
||||
} else {
|
||||
patch.logo = null;
|
||||
} else if (removeLogo === "true") {
|
||||
updateData.logo = null;
|
||||
}
|
||||
|
||||
const statusPage = await StatusPageModel.findOneAndUpdate({ teamId, _id: id }, patch, {
|
||||
const statusPage = await StatusPageModel.findOneAndUpdate({ teamId, _id: id }, updateData, {
|
||||
new: true,
|
||||
});
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@ class StatusPageRoutes {
|
||||
this.router.put("/:id", upload.single("logo"), verifyJWT, this.statusPageController.updateStatusPage);
|
||||
|
||||
this.router.get("/:url", this.statusPageController.getStatusPageByUrl);
|
||||
this.router.delete("/:url(*)", verifyJWT, this.statusPageController.deleteStatusPage);
|
||||
this.router.delete("/:id", verifyJWT, this.statusPageController.deleteStatusPage);
|
||||
}
|
||||
|
||||
getRouter() {
|
||||
|
||||
@@ -2,6 +2,11 @@ export const StatusPageTypes = ["uptime"] as const;
|
||||
export type StatusPageType = (typeof StatusPageTypes)[number];
|
||||
|
||||
export interface StatusPageLogo {
|
||||
data: string;
|
||||
contentType: string;
|
||||
}
|
||||
|
||||
export interface StatusPageLogoDocument {
|
||||
data: Buffer;
|
||||
contentType: string;
|
||||
}
|
||||
|
||||
@@ -480,6 +480,7 @@ const createStatusPageBodyValidation = joi.object({
|
||||
showCharts: joi.boolean().optional(),
|
||||
showUptimePercentage: joi.boolean(),
|
||||
showAdminLoginLink: joi.boolean().optional(),
|
||||
removeLogo: joi.string().valid("true", "false").optional(),
|
||||
});
|
||||
|
||||
const imageValidation = joi
|
||||
|
||||
Reference in New Issue
Block a user