mirror of
https://github.com/hyperdxio/hyperdx
synced 2026-04-21 13:37:15 +00:00
228 lines
5.1 KiB
TypeScript
228 lines
5.1 KiB
TypeScript
import express from 'express';
|
|
import _ from 'lodash';
|
|
import { ObjectId } from 'mongodb';
|
|
import { z } from 'zod';
|
|
import { validateRequest } from 'zod-express-middleware';
|
|
|
|
import { getRecentAlertHistories } from '@/controllers/alertHistory';
|
|
import {
|
|
createAlert,
|
|
deleteAlert,
|
|
getAlertById,
|
|
getAlertsEnhanced,
|
|
updateAlert,
|
|
} from '@/controllers/alerts';
|
|
import { alertSchema, objectIdSchema } from '@/utils/zod';
|
|
|
|
const router = express.Router();
|
|
|
|
router.get('/', async (req, res, next) => {
|
|
try {
|
|
const teamId = req.user?.team;
|
|
if (teamId == null) {
|
|
return res.sendStatus(403);
|
|
}
|
|
|
|
const alerts = await getAlertsEnhanced(teamId);
|
|
|
|
const data = await Promise.all(
|
|
alerts.map(async alert => {
|
|
const history = await getRecentAlertHistories({
|
|
alertId: new ObjectId(alert._id),
|
|
limit: 20,
|
|
});
|
|
|
|
return {
|
|
history,
|
|
silenced: alert.silenced
|
|
? {
|
|
by: alert.silenced.by?.email,
|
|
at: alert.silenced.at,
|
|
until: alert.silenced.until,
|
|
}
|
|
: undefined,
|
|
createdBy: alert.createdBy
|
|
? _.pick(alert.createdBy, ['email', 'name'])
|
|
: undefined,
|
|
channel: _.pick(alert.channel, ['type']),
|
|
...(alert.dashboard && {
|
|
dashboardId: alert.dashboard._id,
|
|
dashboard: {
|
|
tiles: alert.dashboard.tiles
|
|
.filter(tile => tile.id === alert.tileId)
|
|
.map(tile => _.pick(tile, ['id', 'config.name'])),
|
|
..._.pick(alert.dashboard, ['_id', 'name', 'updatedAt', 'tags']),
|
|
},
|
|
}),
|
|
...(alert.savedSearch && {
|
|
savedSearchId: alert.savedSearch._id,
|
|
savedSearch: _.pick(alert.savedSearch, [
|
|
'_id',
|
|
'createdAt',
|
|
'name',
|
|
'updatedAt',
|
|
'tags',
|
|
]),
|
|
}),
|
|
..._.pick(alert, [
|
|
'_id',
|
|
'interval',
|
|
'threshold',
|
|
'thresholdType',
|
|
'state',
|
|
'source',
|
|
'tileId',
|
|
'createdAt',
|
|
'updatedAt',
|
|
]),
|
|
};
|
|
}),
|
|
);
|
|
res.json({
|
|
data,
|
|
});
|
|
} catch (e) {
|
|
next(e);
|
|
}
|
|
});
|
|
|
|
router.post(
|
|
'/',
|
|
validateRequest({ body: alertSchema }),
|
|
async (req, res, next) => {
|
|
const teamId = req.user?.team;
|
|
const userId = req.user?._id;
|
|
if (teamId == null || userId == null) {
|
|
return res.sendStatus(403);
|
|
}
|
|
try {
|
|
const alertInput = req.body;
|
|
return res.json({
|
|
data: await createAlert(teamId, alertInput, userId),
|
|
});
|
|
} catch (e) {
|
|
next(e);
|
|
}
|
|
},
|
|
);
|
|
|
|
router.put(
|
|
'/:id',
|
|
validateRequest({
|
|
body: alertSchema,
|
|
params: z.object({
|
|
id: objectIdSchema,
|
|
}),
|
|
}),
|
|
async (req, res, next) => {
|
|
try {
|
|
const teamId = req.user?.team;
|
|
if (teamId == null) {
|
|
return res.sendStatus(403);
|
|
}
|
|
const { id } = req.params;
|
|
const alertInput = req.body;
|
|
res.json({
|
|
data: await updateAlert(id, teamId, alertInput),
|
|
});
|
|
} catch (e) {
|
|
next(e);
|
|
}
|
|
},
|
|
);
|
|
|
|
router.post(
|
|
'/:id/silenced',
|
|
validateRequest({
|
|
body: z.object({
|
|
mutedUntil: z
|
|
.string()
|
|
.datetime()
|
|
.refine(val => new Date(val) > new Date(), {
|
|
message: 'mutedUntil must be in the future',
|
|
}),
|
|
}),
|
|
params: z.object({
|
|
id: objectIdSchema,
|
|
}),
|
|
}),
|
|
async (req, res, next) => {
|
|
try {
|
|
const teamId = req.user?.team;
|
|
if (teamId == null || req.user == null) {
|
|
return res.sendStatus(403);
|
|
}
|
|
|
|
const alert = await getAlertById(req.params.id, teamId);
|
|
if (!alert) {
|
|
return res.status(404).json({ error: 'Alert not found' });
|
|
}
|
|
alert.silenced = {
|
|
by: req.user._id,
|
|
at: new Date(),
|
|
until: new Date(req.body.mutedUntil),
|
|
};
|
|
await alert.save();
|
|
|
|
res.sendStatus(200);
|
|
} catch (e) {
|
|
next(e);
|
|
}
|
|
},
|
|
);
|
|
|
|
router.delete(
|
|
'/:id/silenced',
|
|
validateRequest({
|
|
params: z.object({
|
|
id: objectIdSchema,
|
|
}),
|
|
}),
|
|
async (req, res, next) => {
|
|
try {
|
|
const teamId = req.user?.team;
|
|
if (teamId == null) {
|
|
return res.sendStatus(403);
|
|
}
|
|
|
|
const alert = await getAlertById(req.params.id, teamId);
|
|
if (!alert) {
|
|
return res.status(404).json({ error: 'Alert not found' });
|
|
}
|
|
alert.silenced = undefined;
|
|
await alert.save();
|
|
|
|
res.sendStatus(200);
|
|
} catch (e) {
|
|
next(e);
|
|
}
|
|
},
|
|
);
|
|
|
|
router.delete(
|
|
'/:id',
|
|
validateRequest({
|
|
params: z.object({
|
|
id: objectIdSchema,
|
|
}),
|
|
}),
|
|
async (req, res, next) => {
|
|
try {
|
|
const teamId = req.user?.team;
|
|
const { id: alertId } = req.params;
|
|
if (teamId == null) {
|
|
return res.sendStatus(403);
|
|
}
|
|
if (!alertId) {
|
|
return res.sendStatus(400);
|
|
}
|
|
|
|
await deleteAlert(alertId, teamId);
|
|
res.sendStatus(200);
|
|
} catch (e) {
|
|
next(e);
|
|
}
|
|
},
|
|
);
|
|
|
|
export default router;
|