mirror of
https://github.com/hyperdxio/hyperdx
synced 2026-04-21 13:37:15 +00:00
fix: GET alerts endpoint (#220)
This commit is contained in:
parent
e2c02985fc
commit
76d7d73b29
6 changed files with 82 additions and 18 deletions
6
.changeset/wild-plants-drop.md
Normal file
6
.changeset/wild-plants-drop.md
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
---
|
||||
'@hyperdx/api': patch
|
||||
'@hyperdx/app': patch
|
||||
---
|
||||
|
||||
fix: GET alerts endpoint
|
||||
|
|
@ -3,6 +3,7 @@ import ms from 'ms';
|
|||
|
||||
import * as clickhouse from '@/clickhouse';
|
||||
import { SQLSerializer } from '@/clickhouse/searchQueryParser';
|
||||
import type { ObjectId } from '@/models';
|
||||
import Alert, {
|
||||
AlertChannel,
|
||||
AlertInterval,
|
||||
|
|
@ -76,11 +77,11 @@ export const validateGroupByProperty = async ({
|
|||
|
||||
const makeAlert = (alert: AlertInput) => {
|
||||
return {
|
||||
source: alert.source,
|
||||
channel: alert.channel,
|
||||
interval: alert.interval,
|
||||
type: alert.type,
|
||||
source: alert.source,
|
||||
threshold: alert.threshold,
|
||||
type: alert.type,
|
||||
// Log alerts
|
||||
logView: alert.logViewId,
|
||||
groupBy: alert.groupBy,
|
||||
|
|
@ -92,12 +93,20 @@ const makeAlert = (alert: AlertInput) => {
|
|||
};
|
||||
};
|
||||
|
||||
export const createAlert = async (alertInput: AlertInput) => {
|
||||
return new Alert(makeAlert(alertInput)).save();
|
||||
export const createAlert = async (teamId: ObjectId, alertInput: AlertInput) => {
|
||||
return new Alert({
|
||||
...makeAlert(alertInput),
|
||||
team: teamId,
|
||||
}).save();
|
||||
};
|
||||
|
||||
// create an update alert function based off of the above create alert function
|
||||
export const updateAlert = async (id: string, alertInput: AlertInput) => {
|
||||
export const updateAlert = async (
|
||||
id: string,
|
||||
teamId: ObjectId,
|
||||
alertInput: AlertInput,
|
||||
) => {
|
||||
// TODO: find by id and teamId
|
||||
// should consider clearing AlertHistory when updating an alert?
|
||||
return Alert.findByIdAndUpdate(id, makeAlert(alertInput), {
|
||||
returnDocument: 'after',
|
||||
|
|
|
|||
|
|
@ -34,11 +34,12 @@ export interface IAlert {
|
|||
channel: AlertChannel;
|
||||
cron: string;
|
||||
interval: AlertInterval;
|
||||
source?: AlertSource;
|
||||
state: AlertState;
|
||||
team: ObjectId;
|
||||
threshold: number;
|
||||
timezone: string;
|
||||
type: AlertType;
|
||||
source?: AlertSource;
|
||||
|
||||
// Log alerts
|
||||
groupBy?: string;
|
||||
|
|
@ -85,6 +86,10 @@ const AlertSchema = new Schema<IAlert>(
|
|||
required: false,
|
||||
default: 'LOG',
|
||||
},
|
||||
team: {
|
||||
type: mongoose.Schema.Types.ObjectId,
|
||||
ref: 'Team',
|
||||
},
|
||||
|
||||
// Log alerts
|
||||
logView: {
|
||||
|
|
|
|||
|
|
@ -11,8 +11,8 @@ import {
|
|||
import { getTeam } from '@/controllers/team';
|
||||
import Alert from '@/models/alert';
|
||||
import AlertHistory from '@/models/alertHistory';
|
||||
import { IDashboard } from '@/models/dashboard';
|
||||
import { ILogView } from '@/models/logView';
|
||||
import Dashboard, { IDashboard } from '@/models/dashboard';
|
||||
import LogView, { ILogView } from '@/models/logView';
|
||||
|
||||
const router = express.Router();
|
||||
|
||||
|
|
@ -82,7 +82,27 @@ router.get('/', async (req, res, next) => {
|
|||
if (teamId == null) {
|
||||
return res.sendStatus(403);
|
||||
}
|
||||
const alerts = await Alert.find({ team: teamId }).populate<{
|
||||
|
||||
// TODO: to use team field in the alert model
|
||||
const [dashboards, logViews] = await Promise.all([
|
||||
Dashboard.find({ team: teamId }, { _id: 1 }),
|
||||
LogView.find({ team: teamId }, { _id: 1 }),
|
||||
]);
|
||||
|
||||
const alerts = await Alert.find({
|
||||
$or: [
|
||||
{
|
||||
logView: {
|
||||
$in: logViews.map(logView => logView._id),
|
||||
},
|
||||
},
|
||||
{
|
||||
dashboardId: {
|
||||
$in: dashboards.map(dashboard => dashboard._id),
|
||||
},
|
||||
},
|
||||
],
|
||||
}).populate<{
|
||||
logView: ILogView;
|
||||
dashboardId: IDashboard;
|
||||
}>(['logView', 'dashboardId']);
|
||||
|
|
@ -92,7 +112,6 @@ router.get('/', async (req, res, next) => {
|
|||
const history = await AlertHistory.find(
|
||||
{
|
||||
alert: alert._id,
|
||||
team: teamId,
|
||||
},
|
||||
{
|
||||
__v: 0,
|
||||
|
|
@ -105,16 +124,30 @@ router.get('/', async (req, res, next) => {
|
|||
|
||||
return {
|
||||
history,
|
||||
dashboard: alert.dashboardId,
|
||||
channel: _.pick(alert.channel, ['type']),
|
||||
...(alert.dashboardId && {
|
||||
dashboard: {
|
||||
charts: alert.dashboardId.charts
|
||||
.filter(chart => chart.id === alert.chartId)
|
||||
.map(chart => _.pick(chart, ['id', 'name'])),
|
||||
..._.pick(alert.dashboardId, ['_id', 'name', 'updatedAt']),
|
||||
},
|
||||
}),
|
||||
...(alert.logView && {
|
||||
logView: _.pick(alert.logView, [
|
||||
'_id',
|
||||
'createdAt',
|
||||
'name',
|
||||
'updatedAt',
|
||||
]),
|
||||
}),
|
||||
..._.pick(alert, [
|
||||
'_id',
|
||||
'channel',
|
||||
'interval',
|
||||
'threshold',
|
||||
'state',
|
||||
'type',
|
||||
'source',
|
||||
'logView',
|
||||
'chartId',
|
||||
'createdAt',
|
||||
'updatedAt',
|
||||
|
|
@ -135,10 +168,14 @@ router.post(
|
|||
validateRequest({ body: zAlert }),
|
||||
validateGroupBy,
|
||||
async (req, res, next) => {
|
||||
const teamId = req.user?.team;
|
||||
if (teamId == null) {
|
||||
return res.sendStatus(403);
|
||||
}
|
||||
try {
|
||||
const alertInput = req.body;
|
||||
return res.json({
|
||||
data: await createAlert(alertInput),
|
||||
data: await createAlert(teamId, alertInput),
|
||||
});
|
||||
} catch (e) {
|
||||
next(e);
|
||||
|
|
@ -152,10 +189,14 @@ router.put(
|
|||
validateGroupBy,
|
||||
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, alertInput),
|
||||
data: await updateAlert(id, teamId, alertInput),
|
||||
});
|
||||
} catch (e) {
|
||||
next(e);
|
||||
|
|
@ -173,6 +214,7 @@ router.delete('/:id', async (req, res, next) => {
|
|||
if (!alertId) {
|
||||
return res.sendStatus(400);
|
||||
}
|
||||
// FIXME: should add teamId to the find query
|
||||
await Alert.findByIdAndDelete(alertId);
|
||||
res.sendStatus(200);
|
||||
} catch (e) {
|
||||
|
|
|
|||
|
|
@ -71,6 +71,7 @@ router.patch('/:id', async (req, res, next) => {
|
|||
if (!logViewId || !query) {
|
||||
return res.sendStatus(400);
|
||||
}
|
||||
// TODO: query teamId
|
||||
const logView = await LogView.findByIdAndUpdate(
|
||||
logViewId,
|
||||
{
|
||||
|
|
@ -96,6 +97,7 @@ router.delete('/:id', async (req, res, next) => {
|
|||
if (!logViewId) {
|
||||
return res.sendStatus(400);
|
||||
}
|
||||
// TODO: query teamId
|
||||
// delete all alerts
|
||||
await Alert.deleteMany({ logView: logViewId });
|
||||
await LogView.findByIdAndDelete(logViewId);
|
||||
|
|
|
|||
|
|
@ -179,7 +179,7 @@ describe('checkAlerts', () => {
|
|||
url: 'https://hooks.slack.com/services/123',
|
||||
name: 'My Webhook',
|
||||
}).save();
|
||||
const alert = await createAlert({
|
||||
const alert = await createAlert(team._id, {
|
||||
source: 'LOG',
|
||||
channel: {
|
||||
type: 'webhook',
|
||||
|
|
@ -353,7 +353,7 @@ describe('checkAlerts', () => {
|
|||
},
|
||||
],
|
||||
}).save();
|
||||
const alert = await createAlert({
|
||||
const alert = await createAlert(team._id, {
|
||||
source: 'CHART',
|
||||
channel: {
|
||||
type: 'webhook',
|
||||
|
|
@ -586,7 +586,7 @@ describe('checkAlerts', () => {
|
|||
},
|
||||
],
|
||||
}).save();
|
||||
const alert = await createAlert({
|
||||
const alert = await createAlert(team._id, {
|
||||
source: 'CHART',
|
||||
channel: {
|
||||
type: 'webhook',
|
||||
|
|
|
|||
Loading…
Reference in a new issue