@backstage/plugin-notifications-backend 0.6.10-next.1 → 0.6.10-next.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
# @backstage/plugin-notifications-backend
|
|
2
2
|
|
|
3
|
+
## 0.6.10-next.2
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 8ba34e8: Persist notification payload metadata for user notifications and broadcasts, and return it when reading notifications. Re-sending a scoped notification replaces its metadata, or clears it when the new payload omits metadata.
|
|
8
|
+
- Updated dependencies
|
|
9
|
+
- @backstage/backend-plugin-api@1.11.0-next.2
|
|
10
|
+
|
|
3
11
|
## 0.6.10-next.1
|
|
4
12
|
|
|
5
13
|
### Patch Changes
|
|
@@ -27,7 +27,8 @@ const NOTIFICATION_COLUMNS = [
|
|
|
27
27
|
"updated",
|
|
28
28
|
"user",
|
|
29
29
|
"read",
|
|
30
|
-
"saved"
|
|
30
|
+
"saved",
|
|
31
|
+
"metadata"
|
|
31
32
|
];
|
|
32
33
|
const normalizeSeverity = (input) => {
|
|
33
34
|
let lower = (input ?? "normal").toLowerCase();
|
|
@@ -78,7 +79,8 @@ class DatabaseNotificationsStore {
|
|
|
78
79
|
topic: row.topic,
|
|
79
80
|
severity: row.severity,
|
|
80
81
|
scope: row.scope,
|
|
81
|
-
icon: row.icon
|
|
82
|
+
icon: row.icon,
|
|
83
|
+
metadata: row.metadata ? JSON.parse(row.metadata) : void 0
|
|
82
84
|
}
|
|
83
85
|
}));
|
|
84
86
|
};
|
|
@@ -138,6 +140,7 @@ class DatabaseNotificationsStore {
|
|
|
138
140
|
severity: normalizeSeverity(notification.payload?.severity),
|
|
139
141
|
scope: notification.payload?.scope,
|
|
140
142
|
icon: notification.payload.icon,
|
|
143
|
+
metadata: notification.payload?.metadata ? JSON.stringify(notification.payload.metadata) : null,
|
|
141
144
|
saved: notification.saved,
|
|
142
145
|
read: notification.read
|
|
143
146
|
};
|
|
@@ -153,7 +156,8 @@ class DatabaseNotificationsStore {
|
|
|
153
156
|
description: notification.payload?.description,
|
|
154
157
|
severity: normalizeSeverity(notification.payload?.severity),
|
|
155
158
|
icon: notification.payload.icon,
|
|
156
|
-
scope: notification.payload?.scope
|
|
159
|
+
scope: notification.payload?.scope,
|
|
160
|
+
metadata: notification.payload?.metadata ? JSON.stringify(notification.payload.metadata) : null
|
|
157
161
|
};
|
|
158
162
|
};
|
|
159
163
|
getBroadcastUnion = (user) => {
|
|
@@ -285,6 +289,7 @@ class DatabaseNotificationsStore {
|
|
|
285
289
|
}) {
|
|
286
290
|
const updateColumns = {
|
|
287
291
|
title: notification.payload.title,
|
|
292
|
+
metadata: notification.payload.metadata ? JSON.stringify(notification.payload.metadata) : null,
|
|
288
293
|
description: notification.payload.description,
|
|
289
294
|
link: notification.payload.link,
|
|
290
295
|
topic: notification.payload.topic,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DatabaseNotificationsStore.cjs.js","sources":["../../src/database/DatabaseNotificationsStore.ts"],"sourcesContent":["/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport {\n DatabaseService,\n resolvePackagePath,\n} from '@backstage/backend-plugin-api';\nimport {\n NotificationGetOptions,\n NotificationModifyOptions,\n NotificationsStore,\n TopicGetOptions,\n} from './NotificationsStore';\nimport {\n Notification,\n NotificationSettings,\n notificationSeverities,\n NotificationSeverity,\n} from '@backstage/plugin-notifications-common';\nimport { Knex } from 'knex';\nimport crypto from 'node:crypto';\nimport { durationToMilliseconds, HumanDuration } from '@backstage/types';\n\nconst migrationsDir = resolvePackagePath(\n '@backstage/plugin-notifications-backend',\n 'migrations',\n);\n\nconst NOTIFICATION_COLUMNS = [\n 'id',\n 'title',\n 'description',\n 'severity',\n 'link',\n 'origin',\n 'scope',\n 'topic',\n 'icon',\n 'created',\n 'updated',\n 'user',\n 'read',\n 'saved',\n];\n\ntype NotificationRowType = {\n id: string;\n user: string;\n title: string;\n description?: string | null;\n severity: string;\n link: string | null;\n origin: string;\n scope: string | null;\n topic: string | null;\n created: Date;\n updated: Date | null;\n read: Date | null;\n saved: Date | null;\n icon: string | null;\n};\n\ntype BroadcastRowType = {\n id: string;\n title: string;\n description: string | null;\n link: string | null;\n origin: string;\n scope: string | null;\n topic: string | null;\n created: Date;\n updated: Date | null;\n icon: string | null;\n};\n\ntype BroadcastUserStatusRowType = {\n broadcast_id: string;\n user: string;\n read: Date | null;\n saved: Date | null;\n};\n\ntype UserSettingsRowType = {\n user: string;\n channel: string;\n origin: string;\n enabled: boolean;\n};\n\nexport const normalizeSeverity = (input?: string): NotificationSeverity => {\n let lower = (input ?? 'normal').toLowerCase() as NotificationSeverity;\n if (notificationSeverities.indexOf(lower) < 0) {\n lower = 'normal';\n }\n return lower;\n};\n\nexport const generateSettingsHash = (\n user: string,\n channel: string,\n origin: string,\n topic: string | null,\n): string => {\n const rawKey = `${user}|${channel}|${origin}|${topic ?? ''}`;\n return crypto.createHash('sha256').update(rawKey).digest('hex');\n};\n\n/** @internal */\nexport class DatabaseNotificationsStore implements NotificationsStore {\n private readonly isSQLite = false;\n\n private readonly db: Knex;\n\n private constructor(db: Knex) {\n this.db = db;\n this.isSQLite = this.db.client.config.client.includes('sqlite3');\n }\n\n static async create({\n database,\n skipMigrations,\n }: {\n database: DatabaseService;\n skipMigrations?: boolean;\n }): Promise<DatabaseNotificationsStore> {\n const client = await database.getClient();\n\n if (!database.migrations?.skip && !skipMigrations) {\n await client.migrate.latest({\n directory: migrationsDir,\n });\n }\n\n return new DatabaseNotificationsStore(client);\n }\n\n private mapToInteger = (val: string | number | undefined): number => {\n return typeof val === 'string' ? Number.parseInt(val, 10) : val ?? 0;\n };\n\n private mapToNotifications = (rows: any[]): Notification[] => {\n return rows.map(row => ({\n id: row.id,\n user: row.type === 'broadcast' ? null : row.user,\n created: new Date(row.created),\n saved: row.saved,\n read: row.read,\n updated: row.updated,\n origin: row.origin,\n payload: {\n title: row.title,\n description: row.description,\n link: row.link,\n topic: row.topic,\n severity: row.severity,\n scope: row.scope,\n icon: row.icon,\n },\n }));\n };\n\n private mapToNotificationSettings = (rows: any[]): NotificationSettings => {\n return rows.reduce(\n (acc, row) => {\n let chan = acc.channels.find(\n (channel: { id: string }) => channel.id === row.channel,\n );\n if (!chan) {\n acc.channels.push({\n id: row.channel,\n origins: [],\n });\n chan = acc.channels[acc.channels.length - 1];\n }\n let origin = chan.origins.find(\n (ori: { id: string }) => ori.id === row.origin,\n );\n if (!origin) {\n origin = {\n id: row.origin,\n enabled: true,\n topics: [],\n };\n chan.origins.push(origin);\n }\n if (row.topic === null) {\n origin.enabled = Boolean(row.enabled);\n } else {\n let topic = origin.topics.find(\n (top: { id: string }) => top.id === row.topic,\n );\n if (!topic) {\n topic = {\n id: row.topic,\n enabled: Boolean(row.enabled),\n };\n origin.topics.push(topic);\n }\n }\n return acc;\n },\n { channels: [] },\n );\n };\n\n private mapNotificationToDbRow = (notification: Notification) => {\n return {\n id: notification.id,\n user: notification.user,\n origin: notification.origin,\n created: notification.created,\n topic: notification.payload?.topic,\n link: notification.payload?.link,\n title: notification.payload?.title,\n description: notification.payload?.description,\n severity: normalizeSeverity(notification.payload?.severity),\n scope: notification.payload?.scope,\n icon: notification.payload.icon,\n saved: notification.saved,\n read: notification.read,\n };\n };\n\n private mapBroadcastToDbRow = (notification: Notification) => {\n return {\n id: notification.id,\n origin: notification.origin,\n created: notification.created,\n topic: notification.payload?.topic,\n link: notification.payload?.link,\n title: notification.payload?.title,\n description: notification.payload?.description,\n severity: normalizeSeverity(notification.payload?.severity),\n icon: notification.payload.icon,\n scope: notification.payload?.scope,\n };\n };\n\n private getBroadcastUnion = (user?: string | null) => {\n return this.db<BroadcastRowType>('broadcast')\n .leftJoin('broadcast_user_status', function clause() {\n const join = this.on('id', '=', 'broadcast_user_status.broadcast_id');\n if (user !== null && user !== undefined) {\n join.andOnVal('user', '=', user);\n }\n })\n .select([...NOTIFICATION_COLUMNS, this.db.raw(\"'broadcast' as type\")]);\n };\n\n private getNotificationsBaseQuery = (\n options: NotificationGetOptions | NotificationModifyOptions,\n ) => {\n const { user, orderField } = options;\n\n const subQuery = this.db<NotificationRowType>('notification')\n .select([...NOTIFICATION_COLUMNS, this.db.raw(\"'entity' as type\")])\n .unionAll([this.getBroadcastUnion(user)])\n .as('notifications');\n\n const query = this.db.from(subQuery).where(q => {\n q.where('user', user).orWhereNull('user');\n });\n\n if (orderField && orderField.length > 0) {\n orderField.forEach(orderBy => {\n query.orderBy(orderBy.field, orderBy.order);\n });\n } else if (!orderField) {\n query.orderBy('created', 'desc');\n }\n\n if (options.createdAfter) {\n if (this.isSQLite) {\n query.where('created', '>=', options.createdAfter.valueOf());\n } else {\n query.where('created', '>=', options.createdAfter.toISOString());\n }\n }\n\n if (options.limit !== undefined) {\n query.limit(options.limit);\n }\n\n if (options.offset !== undefined) {\n query.offset(options.offset);\n }\n\n if (options.search) {\n query.whereRaw(\n `(LOWER(title) LIKE LOWER(?) OR LOWER(description) LIKE LOWER(?))`,\n [`%${options.search}%`, `%${options.search}%`],\n );\n }\n\n if (options.ids) {\n query.whereIn('id', options.ids);\n }\n\n if (options.read) {\n query.whereNotNull('read');\n } else if (options.read === false) {\n query.whereNull('read');\n } // or match both if undefined\n\n if (options.topic) {\n query.where('topic', '=', options.topic);\n }\n\n if (options.saved) {\n query.whereNotNull('saved');\n } else if (options.saved === false) {\n query.whereNull('saved');\n } // or match both if undefined\n\n if (options.minimumSeverity !== undefined) {\n const idx = notificationSeverities.indexOf(options.minimumSeverity);\n const equalOrHigher = notificationSeverities.slice(0, idx + 1);\n query.whereIn('severity', equalOrHigher);\n }\n\n return query;\n };\n\n async getNotifications(options: NotificationGetOptions) {\n const notificationQuery = this.getNotificationsBaseQuery(options);\n const notifications = await notificationQuery.select([\n ...NOTIFICATION_COLUMNS,\n 'type',\n ]);\n return this.mapToNotifications(notifications);\n }\n\n async getNotificationsCount(options: NotificationGetOptions) {\n const countOptions: NotificationGetOptions = { ...options };\n countOptions.limit = undefined;\n countOptions.offset = undefined;\n countOptions.orderField = [];\n const notificationQuery = this.getNotificationsBaseQuery(countOptions);\n const response = await notificationQuery.count('id as CNT');\n return Number(response[0].CNT);\n }\n\n async saveNotification(notification: Notification) {\n await this.db\n .insert(this.mapNotificationToDbRow(notification))\n .into('notification');\n }\n\n async saveBroadcast(notification: Notification) {\n await this.db\n .insert(this.mapBroadcastToDbRow(notification))\n .into('broadcast');\n if (notification.saved || notification.read) {\n await this.db\n .insert({\n user: notification.user,\n broadcast_id: notification.id,\n saved: notification.saved,\n read: notification.read,\n })\n .into('broadcast_user_status');\n }\n }\n\n async getStatus(options: NotificationGetOptions) {\n const notificationQuery = this.getNotificationsBaseQuery({\n ...options,\n orderField: [],\n });\n const readSubQuery = notificationQuery\n .clone()\n .count('id')\n .whereNotNull('read')\n .as('READ');\n const unreadSubQuery = notificationQuery\n .clone()\n .count('id')\n .whereNull('read')\n .as('UNREAD');\n\n const query = await notificationQuery\n .select(readSubQuery, unreadSubQuery)\n .first();\n\n return {\n unread: this.mapToInteger((query as any)?.UNREAD),\n read: this.mapToInteger((query as any)?.READ),\n };\n }\n\n async getExistingScopeNotification(options: {\n user: string;\n scope: string;\n origin: string;\n }) {\n const query = this.db<NotificationRowType>('notification')\n .where('user', options.user)\n .where('scope', options.scope)\n .where('origin', options.origin)\n .limit(1);\n\n const rows = await query;\n if (!rows || rows.length === 0) {\n return null;\n }\n return this.mapToNotifications(rows)[0];\n }\n\n async getExistingScopeBroadcast(options: { scope: string; origin: string }) {\n const query = this.db<BroadcastRowType>('broadcast')\n .where('scope', options.scope)\n .where('origin', options.origin)\n .limit(1);\n\n const rows = await query;\n if (!rows || rows.length === 0) {\n return null;\n }\n return this.mapToNotifications(rows)[0];\n }\n\n async restoreExistingNotification({\n id,\n notification,\n }: {\n id: string;\n notification: Notification;\n }) {\n const updateColumns = {\n title: notification.payload.title,\n description: notification.payload.description,\n link: notification.payload.link,\n topic: notification.payload.topic,\n updated: new Date(),\n severity: normalizeSeverity(notification.payload?.severity),\n read: null,\n };\n\n const notificationQuery = this.db('notification')\n .where('id', id)\n .where('user', notification.user);\n const broadcastQuery = this.db('broadcast').where('id', id);\n\n await Promise.all([\n notificationQuery.update(updateColumns),\n broadcastQuery.update({ ...updateColumns, read: undefined }),\n ]);\n\n return await this.getNotification({ id, user: notification.user });\n }\n\n async getNotification(options: {\n id: string;\n user?: string | null;\n }): Promise<Notification | null> {\n const rows = await this.db\n .select('*')\n .from(\n this.db<NotificationRowType>('notification')\n .select([...NOTIFICATION_COLUMNS, this.db.raw(\"'entity' as type\")])\n .unionAll([this.getBroadcastUnion(options.user)])\n .as('notifications'),\n )\n .where('id', options.id)\n .limit(1);\n if (!rows || rows.length === 0) {\n return null;\n }\n return this.mapToNotifications(rows)[0];\n }\n\n private markReadSaved = async (\n ids: string[],\n user: string,\n read?: Date | null,\n saved?: Date | null,\n ) => {\n await this.db<NotificationRowType>('notification')\n .whereIn('id', ids)\n .where('user', user)\n .update({ read, saved });\n\n const broadcasts = this.mapToNotifications(\n await this.db('broadcast').whereIn('id', ids).select(),\n );\n\n if (broadcasts.length > 0)\n if (!this.isSQLite) {\n await this.db<BroadcastUserStatusRowType>('broadcast_user_status')\n .insert(\n broadcasts.map(b => ({\n broadcast_id: b.id,\n user,\n read,\n saved,\n })),\n )\n .onConflict(['broadcast_id', 'user'])\n .merge(['read', 'saved']);\n } else {\n // SQLite does not support upsert so fall back to this (mostly for tests and local dev)\n for (const b of broadcasts) {\n const baseQuery = this.db<BroadcastUserStatusRowType>(\n 'broadcast_user_status',\n )\n .where('broadcast_id', b.id)\n .where('user', user);\n const exists = await baseQuery.clone().limit(1).select().first();\n if (exists) {\n await baseQuery.clone().update({ read, saved });\n } else {\n await baseQuery\n .clone()\n .insert({ broadcast_id: b.id, user, read, saved });\n }\n }\n }\n };\n\n async markRead(options: NotificationModifyOptions): Promise<void> {\n await this.markReadSaved(options.ids, options.user, new Date(), undefined);\n }\n\n async markUnread(options: NotificationModifyOptions): Promise<void> {\n await this.markReadSaved(options.ids, options.user, null, undefined);\n }\n\n async markSaved(options: NotificationModifyOptions): Promise<void> {\n await this.markReadSaved(options.ids, options.user, undefined, new Date());\n }\n\n async markUnsaved(options: NotificationModifyOptions): Promise<void> {\n await this.markReadSaved(options.ids, options.user, undefined, null);\n }\n\n async getUserNotificationOrigins(options: {\n user: string;\n }): Promise<{ origins: string[] }> {\n const rows: { origin: string }[] = await this.db<NotificationRowType>(\n 'notification',\n )\n .where('user', options.user)\n .select('origin')\n .distinct();\n return { origins: rows.map(row => row.origin) };\n }\n\n async getUserNotificationTopics(options: {\n user: string;\n }): Promise<{ topics: { origin: string; topic: string }[] }> {\n const rows: { topic: string; origin: string }[] =\n await this.db<NotificationRowType>('notification')\n .where('user', options.user)\n .select('topic', 'origin')\n .whereNotNull('topic')\n .distinct();\n\n return {\n topics: rows.map(row => ({ origin: row.origin, topic: row.topic })),\n };\n }\n\n async getNotificationSettings(options: {\n user: string;\n origin?: string;\n channel?: string;\n topic?: string;\n }): Promise<NotificationSettings> {\n const settingsQuery = this.db<UserSettingsRowType>('user_settings').where(\n 'user',\n options.user,\n );\n if (options.origin) {\n settingsQuery.where('origin', options.origin);\n }\n\n if (options.channel) {\n settingsQuery.where('channel', options.channel);\n }\n\n if (options.topic) {\n settingsQuery.where('topic', options.topic);\n }\n const settings = await settingsQuery.select();\n return this.mapToNotificationSettings(settings);\n }\n\n async saveNotificationSettings(options: {\n user: string;\n settings: NotificationSettings;\n }): Promise<void> {\n const rows: {\n settings_key_hash: string;\n user: string;\n channel: string;\n origin: string;\n topic: string | null;\n enabled: boolean;\n }[] = [];\n\n options.settings.channels.forEach(channel => {\n channel.origins.forEach(origin => {\n rows.push({\n settings_key_hash: generateSettingsHash(\n options.user,\n channel.id,\n origin.id,\n null,\n ),\n user: options.user,\n channel: channel.id,\n origin: origin.id,\n topic: null,\n enabled: origin.enabled,\n });\n\n origin.topics?.forEach(topic => {\n rows.push({\n settings_key_hash: generateSettingsHash(\n options.user,\n channel.id,\n origin.id,\n topic.id,\n ),\n user: options.user,\n channel: channel.id,\n origin: origin.id,\n topic: topic.id,\n enabled: origin.enabled && topic.enabled,\n });\n });\n });\n });\n\n await this.db<UserSettingsRowType>('user_settings')\n .where('user', options.user)\n .delete();\n await this.db<UserSettingsRowType>('user_settings').insert(rows);\n }\n\n async getTopics(options: TopicGetOptions): Promise<{ topics: string[] }> {\n const notificationQuery = this.getNotificationsBaseQuery({\n ...options,\n orderField: [{ field: 'topic', order: 'asc' }],\n });\n const topics = await notificationQuery\n .whereNotNull('topic')\n .distinct(['topic']);\n return { topics: topics.map(row => row.topic) };\n }\n\n async clearNotifications(options: {\n maxAge: HumanDuration;\n }): Promise<{ deletedCount: number }> {\n const ms = durationToMilliseconds(options.maxAge);\n const now = new Date(new Date().getTime() - ms);\n const notificationsCount = await this.db('notification')\n .where(builder => {\n builder.where('created', '<=', now).whereNull('updated');\n })\n .orWhere('updated', '<=', now)\n .delete();\n const broadcastsCount = await this.db('broadcast')\n .where(builder => {\n builder.where('created', '<=', now).whereNull('updated');\n })\n .orWhere('updated', '<=', now)\n .delete();\n return { deletedCount: notificationsCount + broadcastsCount };\n }\n}\n"],"names":["resolvePackagePath","notificationSeverities","crypto","durationToMilliseconds"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"DatabaseNotificationsStore.cjs.js","sources":["../../src/database/DatabaseNotificationsStore.ts"],"sourcesContent":["/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport {\n DatabaseService,\n resolvePackagePath,\n} from '@backstage/backend-plugin-api';\nimport {\n NotificationGetOptions,\n NotificationModifyOptions,\n NotificationsStore,\n TopicGetOptions,\n} from './NotificationsStore';\nimport {\n Notification,\n NotificationSettings,\n notificationSeverities,\n NotificationSeverity,\n} from '@backstage/plugin-notifications-common';\nimport { Knex } from 'knex';\nimport crypto from 'node:crypto';\nimport { durationToMilliseconds, HumanDuration } from '@backstage/types';\n\nconst migrationsDir = resolvePackagePath(\n '@backstage/plugin-notifications-backend',\n 'migrations',\n);\n\nconst NOTIFICATION_COLUMNS = [\n 'id',\n 'title',\n 'description',\n 'severity',\n 'link',\n 'origin',\n 'scope',\n 'topic',\n 'icon',\n 'created',\n 'updated',\n 'user',\n 'read',\n 'saved',\n 'metadata',\n];\n\ntype NotificationRowType = {\n id: string;\n user: string;\n title: string;\n description?: string | null;\n severity: string;\n link: string | null;\n origin: string;\n scope: string | null;\n topic: string | null;\n created: Date;\n updated: Date | null;\n read: Date | null;\n saved: Date | null;\n icon: string | null;\n metadata: string | null;\n};\n\ntype BroadcastRowType = {\n id: string;\n title: string;\n description: string | null;\n link: string | null;\n origin: string;\n scope: string | null;\n topic: string | null;\n created: Date;\n updated: Date | null;\n icon: string | null;\n metadata: string | null;\n};\n\ntype BroadcastUserStatusRowType = {\n broadcast_id: string;\n user: string;\n read: Date | null;\n saved: Date | null;\n};\n\ntype UserSettingsRowType = {\n user: string;\n channel: string;\n origin: string;\n enabled: boolean;\n};\n\nexport const normalizeSeverity = (input?: string): NotificationSeverity => {\n let lower = (input ?? 'normal').toLowerCase() as NotificationSeverity;\n if (notificationSeverities.indexOf(lower) < 0) {\n lower = 'normal';\n }\n return lower;\n};\n\nexport const generateSettingsHash = (\n user: string,\n channel: string,\n origin: string,\n topic: string | null,\n): string => {\n const rawKey = `${user}|${channel}|${origin}|${topic ?? ''}`;\n return crypto.createHash('sha256').update(rawKey).digest('hex');\n};\n\n/** @internal */\nexport class DatabaseNotificationsStore implements NotificationsStore {\n private readonly isSQLite = false;\n\n private readonly db: Knex;\n\n private constructor(db: Knex) {\n this.db = db;\n this.isSQLite = this.db.client.config.client.includes('sqlite3');\n }\n\n static async create({\n database,\n skipMigrations,\n }: {\n database: DatabaseService;\n skipMigrations?: boolean;\n }): Promise<DatabaseNotificationsStore> {\n const client = await database.getClient();\n\n if (!database.migrations?.skip && !skipMigrations) {\n await client.migrate.latest({\n directory: migrationsDir,\n });\n }\n\n return new DatabaseNotificationsStore(client);\n }\n\n private mapToInteger = (val: string | number | undefined): number => {\n return typeof val === 'string' ? Number.parseInt(val, 10) : val ?? 0;\n };\n\n private mapToNotifications = (rows: any[]): Notification[] => {\n return rows.map(row => ({\n id: row.id,\n user: row.type === 'broadcast' ? null : row.user,\n created: new Date(row.created),\n saved: row.saved,\n read: row.read,\n updated: row.updated,\n origin: row.origin,\n payload: {\n title: row.title,\n description: row.description,\n link: row.link,\n topic: row.topic,\n severity: row.severity,\n scope: row.scope,\n icon: row.icon,\n metadata: row.metadata ? JSON.parse(row.metadata) : undefined,\n },\n }));\n };\n\n private mapToNotificationSettings = (rows: any[]): NotificationSettings => {\n return rows.reduce(\n (acc, row) => {\n let chan = acc.channels.find(\n (channel: { id: string }) => channel.id === row.channel,\n );\n if (!chan) {\n acc.channels.push({\n id: row.channel,\n origins: [],\n });\n chan = acc.channels[acc.channels.length - 1];\n }\n let origin = chan.origins.find(\n (ori: { id: string }) => ori.id === row.origin,\n );\n if (!origin) {\n origin = {\n id: row.origin,\n enabled: true,\n topics: [],\n };\n chan.origins.push(origin);\n }\n if (row.topic === null) {\n origin.enabled = Boolean(row.enabled);\n } else {\n let topic = origin.topics.find(\n (top: { id: string }) => top.id === row.topic,\n );\n if (!topic) {\n topic = {\n id: row.topic,\n enabled: Boolean(row.enabled),\n };\n origin.topics.push(topic);\n }\n }\n return acc;\n },\n { channels: [] },\n );\n };\n\n private mapNotificationToDbRow = (notification: Notification) => {\n return {\n id: notification.id,\n user: notification.user,\n origin: notification.origin,\n created: notification.created,\n topic: notification.payload?.topic,\n link: notification.payload?.link,\n title: notification.payload?.title,\n description: notification.payload?.description,\n severity: normalizeSeverity(notification.payload?.severity),\n scope: notification.payload?.scope,\n icon: notification.payload.icon,\n metadata: notification.payload?.metadata\n ? JSON.stringify(notification.payload.metadata)\n : null,\n saved: notification.saved,\n read: notification.read,\n };\n };\n\n private mapBroadcastToDbRow = (notification: Notification) => {\n return {\n id: notification.id,\n origin: notification.origin,\n created: notification.created,\n topic: notification.payload?.topic,\n link: notification.payload?.link,\n title: notification.payload?.title,\n description: notification.payload?.description,\n severity: normalizeSeverity(notification.payload?.severity),\n icon: notification.payload.icon,\n scope: notification.payload?.scope,\n metadata: notification.payload?.metadata\n ? JSON.stringify(notification.payload.metadata)\n : null,\n };\n };\n\n private getBroadcastUnion = (user?: string | null) => {\n return this.db<BroadcastRowType>('broadcast')\n .leftJoin('broadcast_user_status', function clause() {\n const join = this.on('id', '=', 'broadcast_user_status.broadcast_id');\n if (user !== null && user !== undefined) {\n join.andOnVal('user', '=', user);\n }\n })\n .select([...NOTIFICATION_COLUMNS, this.db.raw(\"'broadcast' as type\")]);\n };\n\n private getNotificationsBaseQuery = (\n options: NotificationGetOptions | NotificationModifyOptions,\n ) => {\n const { user, orderField } = options;\n\n const subQuery = this.db<NotificationRowType>('notification')\n .select([...NOTIFICATION_COLUMNS, this.db.raw(\"'entity' as type\")])\n .unionAll([this.getBroadcastUnion(user)])\n .as('notifications');\n\n const query = this.db.from(subQuery).where(q => {\n q.where('user', user).orWhereNull('user');\n });\n\n if (orderField && orderField.length > 0) {\n orderField.forEach(orderBy => {\n query.orderBy(orderBy.field, orderBy.order);\n });\n } else if (!orderField) {\n query.orderBy('created', 'desc');\n }\n\n if (options.createdAfter) {\n if (this.isSQLite) {\n query.where('created', '>=', options.createdAfter.valueOf());\n } else {\n query.where('created', '>=', options.createdAfter.toISOString());\n }\n }\n\n if (options.limit !== undefined) {\n query.limit(options.limit);\n }\n\n if (options.offset !== undefined) {\n query.offset(options.offset);\n }\n\n if (options.search) {\n query.whereRaw(\n `(LOWER(title) LIKE LOWER(?) OR LOWER(description) LIKE LOWER(?))`,\n [`%${options.search}%`, `%${options.search}%`],\n );\n }\n\n if (options.ids) {\n query.whereIn('id', options.ids);\n }\n\n if (options.read) {\n query.whereNotNull('read');\n } else if (options.read === false) {\n query.whereNull('read');\n } // or match both if undefined\n\n if (options.topic) {\n query.where('topic', '=', options.topic);\n }\n\n if (options.saved) {\n query.whereNotNull('saved');\n } else if (options.saved === false) {\n query.whereNull('saved');\n } // or match both if undefined\n\n if (options.minimumSeverity !== undefined) {\n const idx = notificationSeverities.indexOf(options.minimumSeverity);\n const equalOrHigher = notificationSeverities.slice(0, idx + 1);\n query.whereIn('severity', equalOrHigher);\n }\n\n return query;\n };\n\n async getNotifications(options: NotificationGetOptions) {\n const notificationQuery = this.getNotificationsBaseQuery(options);\n const notifications = await notificationQuery.select([\n ...NOTIFICATION_COLUMNS,\n 'type',\n ]);\n return this.mapToNotifications(notifications);\n }\n\n async getNotificationsCount(options: NotificationGetOptions) {\n const countOptions: NotificationGetOptions = { ...options };\n countOptions.limit = undefined;\n countOptions.offset = undefined;\n countOptions.orderField = [];\n const notificationQuery = this.getNotificationsBaseQuery(countOptions);\n const response = await notificationQuery.count('id as CNT');\n return Number(response[0].CNT);\n }\n\n async saveNotification(notification: Notification) {\n await this.db\n .insert(this.mapNotificationToDbRow(notification))\n .into('notification');\n }\n\n async saveBroadcast(notification: Notification) {\n await this.db\n .insert(this.mapBroadcastToDbRow(notification))\n .into('broadcast');\n if (notification.saved || notification.read) {\n await this.db\n .insert({\n user: notification.user,\n broadcast_id: notification.id,\n saved: notification.saved,\n read: notification.read,\n })\n .into('broadcast_user_status');\n }\n }\n\n async getStatus(options: NotificationGetOptions) {\n const notificationQuery = this.getNotificationsBaseQuery({\n ...options,\n orderField: [],\n });\n const readSubQuery = notificationQuery\n .clone()\n .count('id')\n .whereNotNull('read')\n .as('READ');\n const unreadSubQuery = notificationQuery\n .clone()\n .count('id')\n .whereNull('read')\n .as('UNREAD');\n\n const query = await notificationQuery\n .select(readSubQuery, unreadSubQuery)\n .first();\n\n return {\n unread: this.mapToInteger((query as any)?.UNREAD),\n read: this.mapToInteger((query as any)?.READ),\n };\n }\n\n async getExistingScopeNotification(options: {\n user: string;\n scope: string;\n origin: string;\n }) {\n const query = this.db<NotificationRowType>('notification')\n .where('user', options.user)\n .where('scope', options.scope)\n .where('origin', options.origin)\n .limit(1);\n\n const rows = await query;\n if (!rows || rows.length === 0) {\n return null;\n }\n return this.mapToNotifications(rows)[0];\n }\n\n async getExistingScopeBroadcast(options: { scope: string; origin: string }) {\n const query = this.db<BroadcastRowType>('broadcast')\n .where('scope', options.scope)\n .where('origin', options.origin)\n .limit(1);\n\n const rows = await query;\n if (!rows || rows.length === 0) {\n return null;\n }\n return this.mapToNotifications(rows)[0];\n }\n\n async restoreExistingNotification({\n id,\n notification,\n }: {\n id: string;\n notification: Notification;\n }) {\n const updateColumns = {\n title: notification.payload.title,\n metadata: notification.payload.metadata\n ? JSON.stringify(notification.payload.metadata)\n : null,\n description: notification.payload.description,\n link: notification.payload.link,\n topic: notification.payload.topic,\n updated: new Date(),\n severity: normalizeSeverity(notification.payload?.severity),\n read: null,\n };\n\n const notificationQuery = this.db('notification')\n .where('id', id)\n .where('user', notification.user);\n const broadcastQuery = this.db('broadcast').where('id', id);\n\n await Promise.all([\n notificationQuery.update(updateColumns),\n broadcastQuery.update({ ...updateColumns, read: undefined }),\n ]);\n\n return await this.getNotification({ id, user: notification.user });\n }\n\n async getNotification(options: {\n id: string;\n user?: string | null;\n }): Promise<Notification | null> {\n const rows = await this.db\n .select('*')\n .from(\n this.db<NotificationRowType>('notification')\n .select([...NOTIFICATION_COLUMNS, this.db.raw(\"'entity' as type\")])\n .unionAll([this.getBroadcastUnion(options.user)])\n .as('notifications'),\n )\n .where('id', options.id)\n .limit(1);\n if (!rows || rows.length === 0) {\n return null;\n }\n return this.mapToNotifications(rows)[0];\n }\n\n private markReadSaved = async (\n ids: string[],\n user: string,\n read?: Date | null,\n saved?: Date | null,\n ) => {\n await this.db<NotificationRowType>('notification')\n .whereIn('id', ids)\n .where('user', user)\n .update({ read, saved });\n\n const broadcasts = this.mapToNotifications(\n await this.db('broadcast').whereIn('id', ids).select(),\n );\n\n if (broadcasts.length > 0)\n if (!this.isSQLite) {\n await this.db<BroadcastUserStatusRowType>('broadcast_user_status')\n .insert(\n broadcasts.map(b => ({\n broadcast_id: b.id,\n user,\n read,\n saved,\n })),\n )\n .onConflict(['broadcast_id', 'user'])\n .merge(['read', 'saved']);\n } else {\n // SQLite does not support upsert so fall back to this (mostly for tests and local dev)\n for (const b of broadcasts) {\n const baseQuery = this.db<BroadcastUserStatusRowType>(\n 'broadcast_user_status',\n )\n .where('broadcast_id', b.id)\n .where('user', user);\n const exists = await baseQuery.clone().limit(1).select().first();\n if (exists) {\n await baseQuery.clone().update({ read, saved });\n } else {\n await baseQuery\n .clone()\n .insert({ broadcast_id: b.id, user, read, saved });\n }\n }\n }\n };\n\n async markRead(options: NotificationModifyOptions): Promise<void> {\n await this.markReadSaved(options.ids, options.user, new Date(), undefined);\n }\n\n async markUnread(options: NotificationModifyOptions): Promise<void> {\n await this.markReadSaved(options.ids, options.user, null, undefined);\n }\n\n async markSaved(options: NotificationModifyOptions): Promise<void> {\n await this.markReadSaved(options.ids, options.user, undefined, new Date());\n }\n\n async markUnsaved(options: NotificationModifyOptions): Promise<void> {\n await this.markReadSaved(options.ids, options.user, undefined, null);\n }\n\n async getUserNotificationOrigins(options: {\n user: string;\n }): Promise<{ origins: string[] }> {\n const rows: { origin: string }[] = await this.db<NotificationRowType>(\n 'notification',\n )\n .where('user', options.user)\n .select('origin')\n .distinct();\n return { origins: rows.map(row => row.origin) };\n }\n\n async getUserNotificationTopics(options: {\n user: string;\n }): Promise<{ topics: { origin: string; topic: string }[] }> {\n const rows: { topic: string; origin: string }[] =\n await this.db<NotificationRowType>('notification')\n .where('user', options.user)\n .select('topic', 'origin')\n .whereNotNull('topic')\n .distinct();\n\n return {\n topics: rows.map(row => ({ origin: row.origin, topic: row.topic })),\n };\n }\n\n async getNotificationSettings(options: {\n user: string;\n origin?: string;\n channel?: string;\n topic?: string;\n }): Promise<NotificationSettings> {\n const settingsQuery = this.db<UserSettingsRowType>('user_settings').where(\n 'user',\n options.user,\n );\n if (options.origin) {\n settingsQuery.where('origin', options.origin);\n }\n\n if (options.channel) {\n settingsQuery.where('channel', options.channel);\n }\n\n if (options.topic) {\n settingsQuery.where('topic', options.topic);\n }\n const settings = await settingsQuery.select();\n return this.mapToNotificationSettings(settings);\n }\n\n async saveNotificationSettings(options: {\n user: string;\n settings: NotificationSettings;\n }): Promise<void> {\n const rows: {\n settings_key_hash: string;\n user: string;\n channel: string;\n origin: string;\n topic: string | null;\n enabled: boolean;\n }[] = [];\n\n options.settings.channels.forEach(channel => {\n channel.origins.forEach(origin => {\n rows.push({\n settings_key_hash: generateSettingsHash(\n options.user,\n channel.id,\n origin.id,\n null,\n ),\n user: options.user,\n channel: channel.id,\n origin: origin.id,\n topic: null,\n enabled: origin.enabled,\n });\n\n origin.topics?.forEach(topic => {\n rows.push({\n settings_key_hash: generateSettingsHash(\n options.user,\n channel.id,\n origin.id,\n topic.id,\n ),\n user: options.user,\n channel: channel.id,\n origin: origin.id,\n topic: topic.id,\n enabled: origin.enabled && topic.enabled,\n });\n });\n });\n });\n\n await this.db<UserSettingsRowType>('user_settings')\n .where('user', options.user)\n .delete();\n await this.db<UserSettingsRowType>('user_settings').insert(rows);\n }\n\n async getTopics(options: TopicGetOptions): Promise<{ topics: string[] }> {\n const notificationQuery = this.getNotificationsBaseQuery({\n ...options,\n orderField: [{ field: 'topic', order: 'asc' }],\n });\n const topics = await notificationQuery\n .whereNotNull('topic')\n .distinct(['topic']);\n return { topics: topics.map(row => row.topic) };\n }\n\n async clearNotifications(options: {\n maxAge: HumanDuration;\n }): Promise<{ deletedCount: number }> {\n const ms = durationToMilliseconds(options.maxAge);\n const now = new Date(new Date().getTime() - ms);\n const notificationsCount = await this.db('notification')\n .where(builder => {\n builder.where('created', '<=', now).whereNull('updated');\n })\n .orWhere('updated', '<=', now)\n .delete();\n const broadcastsCount = await this.db('broadcast')\n .where(builder => {\n builder.where('created', '<=', now).whereNull('updated');\n })\n .orWhere('updated', '<=', now)\n .delete();\n return { deletedCount: notificationsCount + broadcastsCount };\n }\n}\n"],"names":["resolvePackagePath","notificationSeverities","crypto","durationToMilliseconds"],"mappings":"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"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright 2026 The Backstage Authors
|
|
3
|
+
*
|
|
4
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
* you may not use this file except in compliance with the License.
|
|
6
|
+
* You may obtain a copy of the License at
|
|
7
|
+
*
|
|
8
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
*
|
|
10
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
* See the License for the specific language governing permissions and
|
|
14
|
+
* limitations under the License.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
// @ts-check
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* @param {import('knex').Knex} knex
|
|
21
|
+
*/
|
|
22
|
+
exports.up = async function up(knex) {
|
|
23
|
+
await knex.schema.alterTable('notification', table => {
|
|
24
|
+
table.text('metadata').nullable();
|
|
25
|
+
});
|
|
26
|
+
await knex.schema.alterTable('broadcast', table => {
|
|
27
|
+
table.text('metadata').nullable();
|
|
28
|
+
});
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* @param {import('knex').Knex} knex
|
|
33
|
+
*/
|
|
34
|
+
exports.down = async function down(knex) {
|
|
35
|
+
await knex.schema.alterTable('notification', table => {
|
|
36
|
+
table.dropColumn('metadata');
|
|
37
|
+
});
|
|
38
|
+
await knex.schema.alterTable('broadcast', table => {
|
|
39
|
+
table.dropColumn('metadata');
|
|
40
|
+
});
|
|
41
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@backstage/plugin-notifications-backend",
|
|
3
|
-
"version": "0.6.10-next.
|
|
3
|
+
"version": "0.6.10-next.2",
|
|
4
4
|
"backstage": {
|
|
5
5
|
"role": "backend-plugin",
|
|
6
6
|
"pluginId": "notifications",
|
|
@@ -46,8 +46,8 @@
|
|
|
46
46
|
"test": "backstage-cli package test"
|
|
47
47
|
},
|
|
48
48
|
"dependencies": {
|
|
49
|
-
"@backstage/backend-openapi-utils": "0.7.3-next.
|
|
50
|
-
"@backstage/backend-plugin-api": "1.11.0-next.
|
|
49
|
+
"@backstage/backend-openapi-utils": "0.7.3-next.2",
|
|
50
|
+
"@backstage/backend-plugin-api": "1.11.0-next.2",
|
|
51
51
|
"@backstage/catalog-model": "1.10.2-next.0",
|
|
52
52
|
"@backstage/config": "1.3.10-next.0",
|
|
53
53
|
"@backstage/errors": "1.3.2-next.0",
|
|
@@ -62,14 +62,14 @@
|
|
|
62
62
|
"p-throttle": "^4.1.1"
|
|
63
63
|
},
|
|
64
64
|
"devDependencies": {
|
|
65
|
-
"@backstage/backend-defaults": "0.18.1-next.
|
|
66
|
-
"@backstage/backend-test-utils": "1.11.8-next.
|
|
65
|
+
"@backstage/backend-defaults": "0.18.1-next.3",
|
|
66
|
+
"@backstage/backend-test-utils": "1.11.8-next.2",
|
|
67
67
|
"@backstage/cli": "0.36.7-next.0",
|
|
68
68
|
"@backstage/plugin-auth-backend": "0.30.2-next.1",
|
|
69
69
|
"@backstage/plugin-auth-backend-module-guest-provider": "0.2.24-next.1",
|
|
70
|
-
"@backstage/plugin-events-backend": "0.6.7-next.
|
|
71
|
-
"@backstage/plugin-signals-backend": "0.3.20-next.
|
|
72
|
-
"@backstage/repo-tools": "0.19.2-next.
|
|
70
|
+
"@backstage/plugin-events-backend": "0.6.7-next.2",
|
|
71
|
+
"@backstage/plugin-signals-backend": "0.3.20-next.2",
|
|
72
|
+
"@backstage/repo-tools": "0.19.2-next.3",
|
|
73
73
|
"@types/express": "^4.17.6",
|
|
74
74
|
"@types/supertest": "^2.0.8",
|
|
75
75
|
"supertest": "^7.0.0"
|