Merge branch 'master' into broadcast_notifications

Signed-off-by: Patrik Oldsberg <poldsberg@gmail.com>
This commit is contained in:
Patrik Oldsberg
2024-03-14 12:10:31 +01:00
committed by GitHub
86 changed files with 483 additions and 192 deletions
@@ -16,7 +16,10 @@
import { TestDatabaseId, TestDatabases } from '@backstage/backend-test-utils';
import { DatabaseNotificationsStore } from './DatabaseNotificationsStore';
import { Knex } from 'knex';
import { Notification } from '@backstage/plugin-notifications-common';
import {
Notification,
NotificationSeverity,
} from '@backstage/plugin-notifications-common';
jest.setTimeout(60_000);
@@ -48,6 +51,7 @@ const id4 = '04e0871e-e60a-4f68-8110-5ae3513f992e';
const id5 = '05e0871e-e60a-4f68-8110-5ae3513f992e';
const id6 = '06e0871e-e60a-4f68-8110-5ae3513f992e';
const id7 = '07e0871e-e60a-4f68-8110-5ae3513f992e';
const ids = [id1, id2, id3, id4, id5, id6, id7];
const now = Date.now();
const timeDelay = 5 * 1000; /* 5 secs */
@@ -269,6 +273,64 @@ describe.each(databases.eachSupportedId())(
});
});
describe('getNotifications filters on severity', () => {
beforeEach(async () => {
const severities: (NotificationSeverity | undefined)[] = [
'normal',
undefined,
'critical',
'high',
'low',
];
await Promise.all(
severities.map((severity, idx) =>
storage.saveNotification({
id: ids[idx],
user,
origin: 'test-origin',
created: new Date(now - idx * timeDelay),
payload: {
title: severity || 'default',
severity,
},
}),
),
);
});
it('normal', async () => {
const normal = await storage.getNotifications({
user,
minimumSeverity: 'normal',
});
expect(normal.map(idOnly)).toEqual([id1, id2, id3, id4]);
});
it('critical', async () => {
const critical = await storage.getNotifications({
user,
minimumSeverity: 'critical',
});
expect(critical.length).toBe(1);
expect(critical.at(0)?.id).toEqual(id3);
});
it('high', async () => {
const high = await storage.getNotifications({
user,
minimumSeverity: 'high',
});
expect(high.map(idOnly)).toEqual([id3, id4]);
});
it('low', async () => {
const low = await storage.getNotifications({
user,
minimumSeverity: 'low',
});
expect(low.map(idOnly)).toEqual([id1, id2, id3, id4, id5]);
});
});
describe('getNotifications pagination', () => {
beforeEach(async () => {
await storage.saveNotification(testNotification1);
@@ -455,13 +517,14 @@ describe.each(databases.eachSupportedId())(
payload: {
title: 'New notification',
link: '/scaffolder/task/1234',
severity: 'normal',
severity: 'low',
},
} as any,
});
expect(existing).not.toBeNull();
expect(existing?.id).toEqual(id2);
expect(existing?.payload.title).toEqual('New notification');
expect(existing?.payload.severity).toEqual('low');
expect(existing?.read).toBeNull();
});
@@ -22,7 +22,10 @@ import {
NotificationModifyOptions,
NotificationsStore,
} from './NotificationsStore';
import { Notification } from '@backstage/plugin-notifications-common';
import {
Notification,
NotificationSeverity,
} from '@backstage/plugin-notifications-common';
import { Knex } from 'knex';
const migrationsDir = resolvePackagePath(
@@ -46,6 +49,21 @@ const NOTIFICATION_COLUMNS = [
'saved',
];
const severities: NotificationSeverity[] = [
'critical',
'high',
'normal',
'low',
];
export const normalizeSeverity = (input?: string): NotificationSeverity => {
let lower = (input ?? 'normal').toLowerCase() as NotificationSeverity;
if (severities.indexOf(lower) < 0) {
lower = 'normal';
}
return lower;
};
/** @internal */
export class DatabaseNotificationsStore implements NotificationsStore {
private isSQLite = false;
@@ -107,7 +125,7 @@ export class DatabaseNotificationsStore implements NotificationsStore {
link: notification.payload?.link,
title: notification.payload?.title,
description: notification.payload?.description,
severity: notification.payload?.severity,
severity: normalizeSeverity(notification.payload?.severity),
scope: notification.payload?.scope,
saved: notification.saved,
read: notification.read,
@@ -198,6 +216,12 @@ export class DatabaseNotificationsStore implements NotificationsStore {
query.whereNull('saved');
} // or match both if undefined
if (options.minimumSeverity !== undefined) {
const idx = severities.indexOf(options.minimumSeverity);
const equalOrHigher = severities.slice(0, idx + 1);
query.whereIn('notification.severity', equalOrHigher);
}
return query;
};
@@ -296,17 +320,20 @@ export class DatabaseNotificationsStore implements NotificationsStore {
return rows[0] as Notification;
}
async restoreExistingNotification(options: {
async restoreExistingNotification({
id,
notification,
}: {
id: string;
notification: Notification;
}) {
const updateColumns = {
title: options.notification.payload.title,
description: options.notification.payload.description,
link: options.notification.payload.link,
topic: options.notification.payload.topic,
title: notification.payload.title,
description: notification.payload.description,
link: notification.payload.link,
topic: notification.payload.topic,
updated: new Date(),
severity: options.notification.payload.severity,
severity: normalizeSeverity(notification.payload?.severity),
read: null,
};
@@ -320,7 +347,7 @@ export class DatabaseNotificationsStore implements NotificationsStore {
broadcastQuery.update({ ...updateColumns, read: undefined }),
]);
return await this.getNotification(options);
return await this.getNotification({ id });
}
async getNotification(options: { id: string }): Promise<Notification | null> {
@@ -16,6 +16,7 @@
import {
Notification,
NotificationSeverity,
NotificationStatus,
} from '@backstage/plugin-notifications-common';
@@ -32,6 +33,7 @@ export type NotificationGetOptions = {
read?: boolean;
saved?: boolean;
createdAfter?: Date;
minimumSeverity?: NotificationSeverity;
};
/** @internal */
@@ -18,6 +18,7 @@ import express, { Request } from 'express';
import Router from 'express-promise-router';
import {
DatabaseNotificationsStore,
normalizeSeverity,
NotificationGetOptions,
} from '../database';
import { v4 as uuid } from 'uuid';
@@ -236,6 +237,11 @@ export async function createRouter(
}
opts.createdAfter = new Date(sinceEpoch);
}
if (req.query.minimal_severity) {
opts.minimumSeverity = normalizeSeverity(
req.query.minimal_severity.toString(),
);
}
const [notifications, totalCount] = await Promise.all([
store.getNotifications(opts),