@backstage/plugin-notifications-backend 0.5.7-next.1 → 0.5.7

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,55 @@
1
1
  # @backstage/plugin-notifications-backend
2
2
 
3
+ ## 0.5.7
4
+
5
+ ### Patch Changes
6
+
7
+ - 41d4d6e: Notifications are now automatically deleted after 1 year by default.
8
+
9
+ There is a new scheduled task that runs every 24 hours to delete notifications older than 1 year.
10
+ This can be configured by setting the `notifications.retention` in the `app-config.yaml` file.
11
+
12
+ ```yaml
13
+ notifications:
14
+ retention: 1y
15
+ ```
16
+
17
+ If the retention is set to false, notifications will not be automatically deleted.
18
+
19
+ - 8a150bf: Internal changes to switch to the non-alpha `catalogServiceRef`
20
+ - 1fb5f06: Adds ability for user to turn on/off notifications for specific topics within an origin.
21
+ - ef9ab82: Notifications API will now return user as null always for broadcast notifications
22
+ - Updated dependencies
23
+ - @backstage/plugin-notifications-common@0.0.9
24
+ - @backstage/plugin-catalog-node@1.17.1
25
+ - @backstage/plugin-auth-node@0.6.4
26
+ - @backstage/backend-plugin-api@1.4.0
27
+ - @backstage/plugin-notifications-node@0.2.16
28
+ - @backstage/catalog-model@1.7.4
29
+ - @backstage/config@1.3.2
30
+ - @backstage/errors@1.2.7
31
+ - @backstage/types@1.2.1
32
+ - @backstage/plugin-events-node@0.4.12
33
+ - @backstage/plugin-signals-node@0.1.21
34
+
35
+ ## 0.5.7-next.2
36
+
37
+ ### Patch Changes
38
+
39
+ - 8a150bf: Internal changes to switch to the non-alpha `catalogServiceRef`
40
+ - Updated dependencies
41
+ - @backstage/backend-plugin-api@1.4.0-next.1
42
+ - @backstage/catalog-model@1.7.4
43
+ - @backstage/config@1.3.2
44
+ - @backstage/errors@1.2.7
45
+ - @backstage/types@1.2.1
46
+ - @backstage/plugin-auth-node@0.6.4-next.1
47
+ - @backstage/plugin-catalog-node@1.17.1-next.1
48
+ - @backstage/plugin-events-node@0.4.12-next.1
49
+ - @backstage/plugin-notifications-common@0.0.9-next.0
50
+ - @backstage/plugin-notifications-node@0.2.16-next.1
51
+ - @backstage/plugin-signals-node@0.1.21-next.1
52
+
3
53
  ## 0.5.7-next.1
4
54
 
5
55
  ### Patch Changes
package/config.d.ts CHANGED
@@ -28,5 +28,10 @@ export interface Config {
28
28
  * Throttle duration between notification sending, defaults to 50ms
29
29
  */
30
30
  throttleInterval?: HumanDuration | string;
31
+ /**
32
+ * Time to keep the notifications in the database, defaults to 365 days.
33
+ * Can be disabled by setting to false.
34
+ */
35
+ retention?: HumanDuration | string | false;
31
36
  };
32
37
  }
@@ -3,6 +3,7 @@
3
3
  var backendPluginApi = require('@backstage/backend-plugin-api');
4
4
  var pluginNotificationsCommon = require('@backstage/plugin-notifications-common');
5
5
  var crypto = require('crypto');
6
+ var types = require('@backstage/types');
6
7
 
7
8
  function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e : { default: e }; }
8
9
 
@@ -63,7 +64,7 @@ class DatabaseNotificationsStore {
63
64
  mapToNotifications = (rows) => {
64
65
  return rows.map((row) => ({
65
66
  id: row.id,
66
- user: row.user,
67
+ user: row.type === "broadcast" ? null : row.user,
67
68
  created: new Date(row.created),
68
69
  saved: row.saved,
69
70
  read: row.read,
@@ -160,11 +161,11 @@ class DatabaseNotificationsStore {
160
161
  if (user !== null && user !== void 0) {
161
162
  join.andOnVal("user", "=", user);
162
163
  }
163
- }).select(NOTIFICATION_COLUMNS);
164
+ }).select([...NOTIFICATION_COLUMNS, this.db.raw("'broadcast' as type")]);
164
165
  };
165
166
  getNotificationsBaseQuery = (options) => {
166
167
  const { user, orderField } = options;
167
- const subQuery = this.db("notification").select(NOTIFICATION_COLUMNS).unionAll([this.getBroadcastUnion(user)]).as("notifications");
168
+ const subQuery = this.db("notification").select([...NOTIFICATION_COLUMNS, this.db.raw("'entity' as type")]).unionAll([this.getBroadcastUnion(user)]).as("notifications");
168
169
  const query = this.db.from(subQuery).where((q) => {
169
170
  q.where("user", user).orWhereNull("user");
170
171
  });
@@ -219,7 +220,10 @@ class DatabaseNotificationsStore {
219
220
  };
220
221
  async getNotifications(options) {
221
222
  const notificationQuery = this.getNotificationsBaseQuery(options);
222
- const notifications = await notificationQuery.select(NOTIFICATION_COLUMNS);
223
+ const notifications = await notificationQuery.select([
224
+ ...NOTIFICATION_COLUMNS,
225
+ "type"
226
+ ]);
223
227
  return this.mapToNotifications(notifications);
224
228
  }
225
229
  async getNotificationsCount(options) {
@@ -297,7 +301,7 @@ class DatabaseNotificationsStore {
297
301
  }
298
302
  async getNotification(options) {
299
303
  const rows = await this.db.select("*").from(
300
- this.db("notification").select(NOTIFICATION_COLUMNS).unionAll([this.getBroadcastUnion(options.user)]).as("notifications")
304
+ this.db("notification").select([...NOTIFICATION_COLUMNS, this.db.raw("'entity' as type")]).unionAll([this.getBroadcastUnion(options.user)]).as("notifications")
301
305
  ).where("id", options.id).limit(1);
302
306
  if (!rows || rows.length === 0) {
303
307
  return null;
@@ -419,6 +423,17 @@ class DatabaseNotificationsStore {
419
423
  const topics = await notificationQuery.whereNotNull("topic").distinct(["topic"]);
420
424
  return { topics: topics.map((row) => row.topic) };
421
425
  }
426
+ async clearNotifications(options) {
427
+ const ms = types.durationToMilliseconds(options.maxAge);
428
+ const now = new Date((/* @__PURE__ */ new Date()).getTime() - ms);
429
+ const notificationsCount = await this.db("notification").where((builder) => {
430
+ builder.where("created", "<=", now).whereNull("updated");
431
+ }).orWhere("updated", "<=", now).delete();
432
+ const broadcastsCount = await this.db("broadcast").where((builder) => {
433
+ builder.where("created", "<=", now).whereNull("updated");
434
+ }).orWhere("updated", "<=", now).delete();
435
+ return { deletedCount: notificationsCount + broadcastsCount };
436
+ }
422
437
  }
423
438
 
424
439
  exports.DatabaseNotificationsStore = DatabaseNotificationsStore;
@@ -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 'crypto';\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 constructor(private readonly db: Knex) {\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.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);\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)\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) {\n query.limit(options.limit);\n }\n\n if (options.offset) {\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(NOTIFICATION_COLUMNS);\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)\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"],"names":["resolvePackagePath","notificationSeverities","crypto"],"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 '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 constructor(private readonly db: Knex) {\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) {\n query.limit(options.limit);\n }\n\n if (options.offset) {\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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"}
@@ -4,7 +4,9 @@ var backendPluginApi = require('@backstage/backend-plugin-api');
4
4
  var router = require('./service/router.cjs.js');
5
5
  var pluginSignalsNode = require('@backstage/plugin-signals-node');
6
6
  var pluginNotificationsNode = require('@backstage/plugin-notifications-node');
7
- var alpha = require('@backstage/plugin-catalog-node/alpha');
7
+ var pluginCatalogNode = require('@backstage/plugin-catalog-node');
8
+ var DatabaseNotificationsStore = require('./database/DatabaseNotificationsStore.cjs.js');
9
+ var NotificationCleaner = require('./service/NotificationCleaner.cjs.js');
8
10
 
9
11
  class NotificationsProcessingExtensionPointImpl {
10
12
  #processors = new Array();
@@ -33,7 +35,8 @@ const notificationsPlugin = backendPluginApi.createBackendPlugin({
33
35
  database: backendPluginApi.coreServices.database,
34
36
  signals: pluginSignalsNode.signalsServiceRef,
35
37
  config: backendPluginApi.coreServices.rootConfig,
36
- catalog: alpha.catalogServiceRef
38
+ catalog: pluginCatalogNode.catalogServiceRef,
39
+ scheduler: backendPluginApi.coreServices.scheduler
37
40
  },
38
41
  async init({
39
42
  auth,
@@ -44,8 +47,10 @@ const notificationsPlugin = backendPluginApi.createBackendPlugin({
44
47
  database,
45
48
  signals,
46
49
  config,
47
- catalog
50
+ catalog,
51
+ scheduler
48
52
  }) {
53
+ const store = await DatabaseNotificationsStore.DatabaseNotificationsStore.create({ database });
49
54
  httpRouter.use(
50
55
  await router.createRouter({
51
56
  auth,
@@ -53,7 +58,7 @@ const notificationsPlugin = backendPluginApi.createBackendPlugin({
53
58
  userInfo,
54
59
  logger,
55
60
  config,
56
- database,
61
+ store,
57
62
  catalog,
58
63
  signals,
59
64
  processors: processingExtensions.processors
@@ -63,6 +68,13 @@ const notificationsPlugin = backendPluginApi.createBackendPlugin({
63
68
  path: "/health",
64
69
  allow: "unauthenticated"
65
70
  });
71
+ const cleaner = new NotificationCleaner.NotificationCleaner(
72
+ config,
73
+ scheduler,
74
+ logger,
75
+ store
76
+ );
77
+ await cleaner.initTaskRunner();
66
78
  }
67
79
  });
68
80
  }
@@ -1 +1 @@
1
- {"version":3,"file":"plugin.cjs.js","sources":["../src/plugin.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 */\n\nimport {\n coreServices,\n createBackendPlugin,\n} from '@backstage/backend-plugin-api';\nimport { createRouter } from './service/router';\nimport { signalsServiceRef } from '@backstage/plugin-signals-node';\nimport {\n NotificationProcessor,\n notificationsProcessingExtensionPoint,\n NotificationsProcessingExtensionPoint,\n} from '@backstage/plugin-notifications-node';\nimport { catalogServiceRef } from '@backstage/plugin-catalog-node/alpha';\n\nclass NotificationsProcessingExtensionPointImpl\n implements NotificationsProcessingExtensionPoint\n{\n #processors = new Array<NotificationProcessor>();\n\n addProcessor(\n ...processors: Array<NotificationProcessor | Array<NotificationProcessor>>\n ): void {\n this.#processors.push(...processors.flat());\n }\n\n get processors() {\n return this.#processors;\n }\n}\n\n/**\n * Notifications backend plugin\n *\n * @public\n */\nexport const notificationsPlugin = createBackendPlugin({\n pluginId: 'notifications',\n register(env) {\n const processingExtensions =\n new NotificationsProcessingExtensionPointImpl();\n env.registerExtensionPoint(\n notificationsProcessingExtensionPoint,\n processingExtensions,\n );\n\n env.registerInit({\n deps: {\n auth: coreServices.auth,\n httpAuth: coreServices.httpAuth,\n userInfo: coreServices.userInfo,\n httpRouter: coreServices.httpRouter,\n logger: coreServices.logger,\n database: coreServices.database,\n signals: signalsServiceRef,\n config: coreServices.rootConfig,\n catalog: catalogServiceRef,\n },\n async init({\n auth,\n httpAuth,\n userInfo,\n httpRouter,\n logger,\n database,\n signals,\n config,\n catalog,\n }) {\n httpRouter.use(\n await createRouter({\n auth,\n httpAuth,\n userInfo,\n logger,\n config,\n database,\n catalog,\n signals,\n processors: processingExtensions.processors,\n }),\n );\n httpRouter.addAuthPolicy({\n path: '/health',\n allow: 'unauthenticated',\n });\n },\n });\n },\n});\n"],"names":["createBackendPlugin","notificationsProcessingExtensionPoint","coreServices","signalsServiceRef","catalogServiceRef","createRouter"],"mappings":";;;;;;;;AA6BA,MAAM,yCAEN,CAAA;AAAA,EACE,WAAA,GAAc,IAAI,KAA6B,EAAA;AAAA,EAE/C,gBACK,UACG,EAAA;AACN,IAAA,IAAA,CAAK,WAAY,CAAA,IAAA,CAAK,GAAG,UAAA,CAAW,MAAM,CAAA;AAAA;AAC5C,EAEA,IAAI,UAAa,GAAA;AACf,IAAA,OAAO,IAAK,CAAA,WAAA;AAAA;AAEhB;AAOO,MAAM,sBAAsBA,oCAAoB,CAAA;AAAA,EACrD,QAAU,EAAA,eAAA;AAAA,EACV,SAAS,GAAK,EAAA;AACZ,IAAM,MAAA,oBAAA,GACJ,IAAI,yCAA0C,EAAA;AAChD,IAAI,GAAA,CAAA,sBAAA;AAAA,MACFC,6DAAA;AAAA,MACA;AAAA,KACF;AAEA,IAAA,GAAA,CAAI,YAAa,CAAA;AAAA,MACf,IAAM,EAAA;AAAA,QACJ,MAAMC,6BAAa,CAAA,IAAA;AAAA,QACnB,UAAUA,6BAAa,CAAA,QAAA;AAAA,QACvB,UAAUA,6BAAa,CAAA,QAAA;AAAA,QACvB,YAAYA,6BAAa,CAAA,UAAA;AAAA,QACzB,QAAQA,6BAAa,CAAA,MAAA;AAAA,QACrB,UAAUA,6BAAa,CAAA,QAAA;AAAA,QACvB,OAAS,EAAAC,mCAAA;AAAA,QACT,QAAQD,6BAAa,CAAA,UAAA;AAAA,QACrB,OAAS,EAAAE;AAAA,OACX;AAAA,MACA,MAAM,IAAK,CAAA;AAAA,QACT,IAAA;AAAA,QACA,QAAA;AAAA,QACA,QAAA;AAAA,QACA,UAAA;AAAA,QACA,MAAA;AAAA,QACA,QAAA;AAAA,QACA,OAAA;AAAA,QACA,MAAA;AAAA,QACA;AAAA,OACC,EAAA;AACD,QAAW,UAAA,CAAA,GAAA;AAAA,UACT,MAAMC,mBAAa,CAAA;AAAA,YACjB,IAAA;AAAA,YACA,QAAA;AAAA,YACA,QAAA;AAAA,YACA,MAAA;AAAA,YACA,MAAA;AAAA,YACA,QAAA;AAAA,YACA,OAAA;AAAA,YACA,OAAA;AAAA,YACA,YAAY,oBAAqB,CAAA;AAAA,WAClC;AAAA,SACH;AACA,QAAA,UAAA,CAAW,aAAc,CAAA;AAAA,UACvB,IAAM,EAAA,SAAA;AAAA,UACN,KAAO,EAAA;AAAA,SACR,CAAA;AAAA;AACH,KACD,CAAA;AAAA;AAEL,CAAC;;;;"}
1
+ {"version":3,"file":"plugin.cjs.js","sources":["../src/plugin.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 */\n\nimport {\n coreServices,\n createBackendPlugin,\n} from '@backstage/backend-plugin-api';\nimport { createRouter } from './service/router';\nimport { signalsServiceRef } from '@backstage/plugin-signals-node';\nimport {\n NotificationProcessor,\n notificationsProcessingExtensionPoint,\n NotificationsProcessingExtensionPoint,\n} from '@backstage/plugin-notifications-node';\nimport { catalogServiceRef } from '@backstage/plugin-catalog-node';\nimport { DatabaseNotificationsStore } from './database';\nimport { NotificationCleaner } from './service/NotificationCleaner.ts';\n\nclass NotificationsProcessingExtensionPointImpl\n implements NotificationsProcessingExtensionPoint\n{\n #processors = new Array<NotificationProcessor>();\n\n addProcessor(\n ...processors: Array<NotificationProcessor | Array<NotificationProcessor>>\n ): void {\n this.#processors.push(...processors.flat());\n }\n\n get processors() {\n return this.#processors;\n }\n}\n\n/**\n * Notifications backend plugin\n *\n * @public\n */\nexport const notificationsPlugin = createBackendPlugin({\n pluginId: 'notifications',\n register(env) {\n const processingExtensions =\n new NotificationsProcessingExtensionPointImpl();\n env.registerExtensionPoint(\n notificationsProcessingExtensionPoint,\n processingExtensions,\n );\n\n env.registerInit({\n deps: {\n auth: coreServices.auth,\n httpAuth: coreServices.httpAuth,\n userInfo: coreServices.userInfo,\n httpRouter: coreServices.httpRouter,\n logger: coreServices.logger,\n database: coreServices.database,\n signals: signalsServiceRef,\n config: coreServices.rootConfig,\n catalog: catalogServiceRef,\n scheduler: coreServices.scheduler,\n },\n async init({\n auth,\n httpAuth,\n userInfo,\n httpRouter,\n logger,\n database,\n signals,\n config,\n catalog,\n scheduler,\n }) {\n const store = await DatabaseNotificationsStore.create({ database });\n\n httpRouter.use(\n await createRouter({\n auth,\n httpAuth,\n userInfo,\n logger,\n config,\n store,\n catalog,\n signals,\n processors: processingExtensions.processors,\n }),\n );\n httpRouter.addAuthPolicy({\n path: '/health',\n allow: 'unauthenticated',\n });\n\n const cleaner = new NotificationCleaner(\n config,\n scheduler,\n logger,\n store,\n );\n await cleaner.initTaskRunner();\n },\n });\n },\n});\n"],"names":["createBackendPlugin","notificationsProcessingExtensionPoint","coreServices","signalsServiceRef","catalogServiceRef","DatabaseNotificationsStore","createRouter","NotificationCleaner"],"mappings":";;;;;;;;;;AA+BA,MAAM,yCAEN,CAAA;AAAA,EACE,WAAA,GAAc,IAAI,KAA6B,EAAA;AAAA,EAE/C,gBACK,UACG,EAAA;AACN,IAAA,IAAA,CAAK,WAAY,CAAA,IAAA,CAAK,GAAG,UAAA,CAAW,MAAM,CAAA;AAAA;AAC5C,EAEA,IAAI,UAAa,GAAA;AACf,IAAA,OAAO,IAAK,CAAA,WAAA;AAAA;AAEhB;AAOO,MAAM,sBAAsBA,oCAAoB,CAAA;AAAA,EACrD,QAAU,EAAA,eAAA;AAAA,EACV,SAAS,GAAK,EAAA;AACZ,IAAM,MAAA,oBAAA,GACJ,IAAI,yCAA0C,EAAA;AAChD,IAAI,GAAA,CAAA,sBAAA;AAAA,MACFC,6DAAA;AAAA,MACA;AAAA,KACF;AAEA,IAAA,GAAA,CAAI,YAAa,CAAA;AAAA,MACf,IAAM,EAAA;AAAA,QACJ,MAAMC,6BAAa,CAAA,IAAA;AAAA,QACnB,UAAUA,6BAAa,CAAA,QAAA;AAAA,QACvB,UAAUA,6BAAa,CAAA,QAAA;AAAA,QACvB,YAAYA,6BAAa,CAAA,UAAA;AAAA,QACzB,QAAQA,6BAAa,CAAA,MAAA;AAAA,QACrB,UAAUA,6BAAa,CAAA,QAAA;AAAA,QACvB,OAAS,EAAAC,mCAAA;AAAA,QACT,QAAQD,6BAAa,CAAA,UAAA;AAAA,QACrB,OAAS,EAAAE,mCAAA;AAAA,QACT,WAAWF,6BAAa,CAAA;AAAA,OAC1B;AAAA,MACA,MAAM,IAAK,CAAA;AAAA,QACT,IAAA;AAAA,QACA,QAAA;AAAA,QACA,QAAA;AAAA,QACA,UAAA;AAAA,QACA,MAAA;AAAA,QACA,QAAA;AAAA,QACA,OAAA;AAAA,QACA,MAAA;AAAA,QACA,OAAA;AAAA,QACA;AAAA,OACC,EAAA;AACD,QAAA,MAAM,QAAQ,MAAMG,qDAAA,CAA2B,MAAO,CAAA,EAAE,UAAU,CAAA;AAElE,QAAW,UAAA,CAAA,GAAA;AAAA,UACT,MAAMC,mBAAa,CAAA;AAAA,YACjB,IAAA;AAAA,YACA,QAAA;AAAA,YACA,QAAA;AAAA,YACA,MAAA;AAAA,YACA,MAAA;AAAA,YACA,KAAA;AAAA,YACA,OAAA;AAAA,YACA,OAAA;AAAA,YACA,YAAY,oBAAqB,CAAA;AAAA,WAClC;AAAA,SACH;AACA,QAAA,UAAA,CAAW,aAAc,CAAA;AAAA,UACvB,IAAM,EAAA,SAAA;AAAA,UACN,KAAO,EAAA;AAAA,SACR,CAAA;AAED,QAAA,MAAM,UAAU,IAAIC,uCAAA;AAAA,UAClB,MAAA;AAAA,UACA,SAAA;AAAA,UACA,MAAA;AAAA,UACA;AAAA,SACF;AACA,QAAA,MAAM,QAAQ,cAAe,EAAA;AAAA;AAC/B,KACD,CAAA;AAAA;AAEL,CAAC;;;;"}
@@ -0,0 +1,63 @@
1
+ 'use strict';
2
+
3
+ var config = require('@backstage/config');
4
+ var errors = require('@backstage/errors');
5
+
6
+ class NotificationCleaner {
7
+ constructor(config$1, scheduler, logger, database) {
8
+ this.scheduler = scheduler;
9
+ this.logger = logger;
10
+ this.database = database;
11
+ if (config$1.has("notifications.retention")) {
12
+ const retentionConfig = config$1.get("notifications.retention");
13
+ if (typeof retentionConfig === "boolean" && !retentionConfig) {
14
+ logger.info(
15
+ "Notification retention is disabled, skipping notification cleaner task"
16
+ );
17
+ this.enabled = false;
18
+ return;
19
+ }
20
+ this.retention = config.readDurationFromConfig(config$1, {
21
+ key: "notifications.retention"
22
+ });
23
+ }
24
+ }
25
+ retention = { years: 1 };
26
+ enabled = true;
27
+ async initTaskRunner() {
28
+ if (!this.enabled) {
29
+ return;
30
+ }
31
+ const schedule = {
32
+ frequency: { cron: "0 0 * * *" },
33
+ timeout: { hours: 1 },
34
+ initialDelay: { hours: 1 },
35
+ scope: "global"
36
+ };
37
+ const taskRunner = this.scheduler.createScheduledTaskRunner(schedule);
38
+ await taskRunner.run({
39
+ id: "notification-cleaner",
40
+ fn: async () => {
41
+ await this.clearNotifications(
42
+ this.logger,
43
+ this.database,
44
+ this.retention
45
+ );
46
+ }
47
+ });
48
+ }
49
+ async clearNotifications(logger, database, retention) {
50
+ logger.info("Starting notification cleaner task");
51
+ try {
52
+ const result = await database.clearNotifications({ maxAge: retention });
53
+ logger.info(
54
+ `Notification cleaner task completed successfully, deleted ${result.deletedCount} notifications`
55
+ );
56
+ } catch (error) {
57
+ throw new errors.ForwardedError("Notification cleaner task failed", error);
58
+ }
59
+ }
60
+ }
61
+
62
+ exports.NotificationCleaner = NotificationCleaner;
63
+ //# sourceMappingURL=NotificationCleaner.cjs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"NotificationCleaner.cjs.js","sources":["../../src/service/NotificationCleaner.ts"],"sourcesContent":["/*\n * Copyright 2025 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 LoggerService,\n SchedulerService,\n SchedulerServiceTaskScheduleDefinition,\n} from '@backstage/backend-plugin-api';\nimport { Config, readDurationFromConfig } from '@backstage/config';\nimport { NotificationsStore } from '../database';\nimport { HumanDuration } from '@backstage/types';\nimport { ForwardedError } from '@backstage/errors';\n\nexport class NotificationCleaner {\n private readonly retention: HumanDuration = { years: 1 };\n private readonly enabled: boolean = true;\n\n constructor(\n config: Config,\n private readonly scheduler: SchedulerService,\n private readonly logger: LoggerService,\n private readonly database: NotificationsStore,\n ) {\n if (config.has('notifications.retention')) {\n const retentionConfig = config.get('notifications.retention');\n if (typeof retentionConfig === 'boolean' && !retentionConfig) {\n logger.info(\n 'Notification retention is disabled, skipping notification cleaner task',\n );\n this.enabled = false;\n return;\n }\n this.retention = readDurationFromConfig(config, {\n key: 'notifications.retention',\n });\n }\n }\n\n async initTaskRunner() {\n if (!this.enabled) {\n return;\n }\n\n const schedule: SchedulerServiceTaskScheduleDefinition = {\n frequency: { cron: '0 0 * * *' },\n timeout: { hours: 1 },\n initialDelay: { hours: 1 },\n scope: 'global',\n };\n\n const taskRunner = this.scheduler.createScheduledTaskRunner(schedule);\n await taskRunner.run({\n id: 'notification-cleaner',\n fn: async () => {\n await this.clearNotifications(\n this.logger,\n this.database,\n this.retention,\n );\n },\n });\n }\n\n private async clearNotifications(\n logger: LoggerService,\n database: NotificationsStore,\n retention: HumanDuration,\n ) {\n logger.info('Starting notification cleaner task');\n try {\n const result = await database.clearNotifications({ maxAge: retention });\n logger.info(\n `Notification cleaner task completed successfully, deleted ${result.deletedCount} notifications`,\n );\n } catch (error) {\n throw new ForwardedError('Notification cleaner task failed', error);\n }\n }\n}\n"],"names":["config","readDurationFromConfig","ForwardedError"],"mappings":";;;;;AAyBO,MAAM,mBAAoB,CAAA;AAAA,EAI/B,WACE,CAAAA,QAAA,EACiB,SACA,EAAA,MAAA,EACA,QACjB,EAAA;AAHiB,IAAA,IAAA,CAAA,SAAA,GAAA,SAAA;AACA,IAAA,IAAA,CAAA,MAAA,GAAA,MAAA;AACA,IAAA,IAAA,CAAA,QAAA,GAAA,QAAA;AAEjB,IAAI,IAAAA,QAAA,CAAO,GAAI,CAAA,yBAAyB,CAAG,EAAA;AACzC,MAAM,MAAA,eAAA,GAAkBA,QAAO,CAAA,GAAA,CAAI,yBAAyB,CAAA;AAC5D,MAAA,IAAI,OAAO,eAAA,KAAoB,SAAa,IAAA,CAAC,eAAiB,EAAA;AAC5D,QAAO,MAAA,CAAA,IAAA;AAAA,UACL;AAAA,SACF;AACA,QAAA,IAAA,CAAK,OAAU,GAAA,KAAA;AACf,QAAA;AAAA;AAEF,MAAK,IAAA,CAAA,SAAA,GAAYC,8BAAuBD,QAAQ,EAAA;AAAA,QAC9C,GAAK,EAAA;AAAA,OACN,CAAA;AAAA;AACH;AACF,EAtBiB,SAAA,GAA2B,EAAE,KAAA,EAAO,CAAE,EAAA;AAAA,EACtC,OAAmB,GAAA,IAAA;AAAA,EAuBpC,MAAM,cAAiB,GAAA;AACrB,IAAI,IAAA,CAAC,KAAK,OAAS,EAAA;AACjB,MAAA;AAAA;AAGF,IAAA,MAAM,QAAmD,GAAA;AAAA,MACvD,SAAA,EAAW,EAAE,IAAA,EAAM,WAAY,EAAA;AAAA,MAC/B,OAAA,EAAS,EAAE,KAAA,EAAO,CAAE,EAAA;AAAA,MACpB,YAAA,EAAc,EAAE,KAAA,EAAO,CAAE,EAAA;AAAA,MACzB,KAAO,EAAA;AAAA,KACT;AAEA,IAAA,MAAM,UAAa,GAAA,IAAA,CAAK,SAAU,CAAA,yBAAA,CAA0B,QAAQ,CAAA;AACpE,IAAA,MAAM,WAAW,GAAI,CAAA;AAAA,MACnB,EAAI,EAAA,sBAAA;AAAA,MACJ,IAAI,YAAY;AACd,QAAA,MAAM,IAAK,CAAA,kBAAA;AAAA,UACT,IAAK,CAAA,MAAA;AAAA,UACL,IAAK,CAAA,QAAA;AAAA,UACL,IAAK,CAAA;AAAA,SACP;AAAA;AACF,KACD,CAAA;AAAA;AACH,EAEA,MAAc,kBAAA,CACZ,MACA,EAAA,QAAA,EACA,SACA,EAAA;AACA,IAAA,MAAA,CAAO,KAAK,oCAAoC,CAAA;AAChD,IAAI,IAAA;AACF,MAAA,MAAM,SAAS,MAAM,QAAA,CAAS,mBAAmB,EAAE,MAAA,EAAQ,WAAW,CAAA;AACtE,MAAO,MAAA,CAAA,IAAA;AAAA,QACL,CAAA,0DAAA,EAA6D,OAAO,YAAY,CAAA,cAAA;AAAA,OAClF;AAAA,aACO,KAAO,EAAA;AACd,MAAM,MAAA,IAAIE,qBAAe,CAAA,kCAAA,EAAoC,KAAK,CAAA;AAAA;AACpE;AAEJ;;;;"}
@@ -10,14 +10,10 @@ const partitionEntityRefs = (refs) => refs.reduce(
10
10
  [[], []]
11
11
  );
12
12
  const getUsersForEntityRef = async (entityRef, excludeEntityRefs, options) => {
13
- const { auth, catalogClient } = options;
13
+ const { auth, catalog } = options;
14
14
  if (entityRef === null) {
15
15
  return [];
16
16
  }
17
- const { token } = await auth.getPluginRequestToken({
18
- onBehalfOf: await auth.getOwnServiceCredentials(),
19
- targetPluginId: "catalog"
20
- });
21
17
  const excluded = Array.isArray(excludeEntityRefs) ? excludeEntityRefs : [excludeEntityRefs];
22
18
  const refsArr = Array.isArray(entityRef) ? entityRef : [entityRef];
23
19
  const [userEntityRefs, otherEntityRefs] = partitionEntityRefs(refsArr);
@@ -26,12 +22,12 @@ const getUsersForEntityRef = async (entityRef, excludeEntityRefs, options) => {
26
22
  const fields = ["kind", "metadata.name", "metadata.namespace", "relations"];
27
23
  let entities = [];
28
24
  if (entityRefs.length > 0) {
29
- const fetchedEntities = await catalogClient.getEntitiesByRefs(
25
+ const fetchedEntities = await catalog.getEntitiesByRefs(
30
26
  {
31
27
  entityRefs,
32
28
  fields
33
29
  },
34
- { token }
30
+ { credentials: await auth.getOwnServiceCredentials() }
35
31
  );
36
32
  entities = fetchedEntities.items;
37
33
  }
@@ -56,12 +52,12 @@ const getUsersForEntityRef = async (entityRef, excludeEntityRefs, options) => {
56
52
  const childGroupRefs = entity.relations.filter((relation) => relation.type === catalogModel.RELATION_PARENT_OF).map((r) => r.targetRef);
57
53
  let childGroupUsers = [];
58
54
  if (childGroupRefs.length > 0) {
59
- const childGroups = await catalogClient.getEntitiesByRefs(
55
+ const childGroups = await catalog.getEntitiesByRefs(
60
56
  {
61
57
  entityRefs: childGroupRefs,
62
58
  fields
63
59
  },
64
- { token }
60
+ { credentials: await auth.getOwnServiceCredentials() }
65
61
  );
66
62
  childGroupUsers = await Promise.all(childGroups.items.map(mapEntity));
67
63
  }
@@ -82,7 +78,9 @@ const getUsersForEntityRef = async (entityRef, excludeEntityRefs, options) => {
82
78
  }
83
79
  return [ownerRef];
84
80
  }
85
- const owner = await catalogClient.getEntityByRef(ownerRef, { token });
81
+ const owner = await catalog.getEntityByRef(ownerRef, {
82
+ credentials: await auth.getOwnServiceCredentials()
83
+ });
86
84
  return mapEntity(owner);
87
85
  }
88
86
  return [];
@@ -1 +1 @@
1
- {"version":3,"file":"getUsersForEntityRef.cjs.js","sources":["../../src/service/getUsersForEntityRef.ts"],"sourcesContent":["/*\n * Copyright 2024 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 Entity,\n isGroupEntity,\n isUserEntity,\n parseEntityRef,\n RELATION_HAS_MEMBER,\n RELATION_OWNED_BY,\n RELATION_PARENT_OF,\n stringifyEntityRef,\n} from '@backstage/catalog-model';\nimport { AuthService } from '@backstage/backend-plugin-api';\nimport { CatalogApi } from '@backstage/catalog-client';\n\nconst isUserEntityRef = (ref: string) =>\n parseEntityRef(ref).kind.toLocaleLowerCase() === 'user';\n\n// Partitions array of entity references to two arrays; user entity refs and other entity refs\nconst partitionEntityRefs = (refs: string[]): string[][] =>\n refs.reduce(\n ([userEntityRefs, otherEntityRefs]: string[][], ref: string) => {\n return isUserEntityRef(ref)\n ? [[...userEntityRefs, ref], otherEntityRefs]\n : [userEntityRefs, [...otherEntityRefs, ref]];\n },\n [[], []],\n );\n\nexport const getUsersForEntityRef = async (\n entityRef: string | string[] | null,\n excludeEntityRefs: string | string[],\n options: {\n auth: AuthService;\n catalogClient: CatalogApi;\n },\n): Promise<string[]> => {\n const { auth, catalogClient } = options;\n\n if (entityRef === null) {\n return [];\n }\n\n const { token } = await auth.getPluginRequestToken({\n onBehalfOf: await auth.getOwnServiceCredentials(),\n targetPluginId: 'catalog',\n });\n\n const excluded = Array.isArray(excludeEntityRefs)\n ? excludeEntityRefs\n : [excludeEntityRefs];\n\n const refsArr = Array.isArray(entityRef) ? entityRef : [entityRef];\n const [userEntityRefs, otherEntityRefs] = partitionEntityRefs(refsArr);\n const users: string[] = userEntityRefs.filter(ref => !excluded.includes(ref));\n const entityRefs = otherEntityRefs.filter(ref => !excluded.includes(ref));\n\n const fields = ['kind', 'metadata.name', 'metadata.namespace', 'relations'];\n let entities: Array<Entity | undefined> = [];\n if (entityRefs.length > 0) {\n const fetchedEntities = await catalogClient.getEntitiesByRefs(\n {\n entityRefs,\n fields,\n },\n { token },\n );\n entities = fetchedEntities.items;\n }\n\n const mapEntity = async (entity: Entity | undefined): Promise<string[]> => {\n if (!entity) {\n return [];\n }\n\n const currentEntityRef = stringifyEntityRef(entity);\n if (excluded.includes(currentEntityRef)) {\n return [];\n }\n\n if (isUserEntity(entity)) {\n return [currentEntityRef];\n }\n\n if (isGroupEntity(entity)) {\n if (!entity.relations?.length) {\n return [];\n }\n\n const groupUsers = entity.relations\n .filter(\n relation =>\n relation.type === RELATION_HAS_MEMBER &&\n isUserEntityRef(relation.targetRef),\n )\n .map(r => r.targetRef);\n\n const childGroupRefs = entity.relations\n .filter(relation => relation.type === RELATION_PARENT_OF)\n .map(r => r.targetRef);\n\n let childGroupUsers: string[][] = [];\n if (childGroupRefs.length > 0) {\n const childGroups = await catalogClient.getEntitiesByRefs(\n {\n entityRefs: childGroupRefs,\n fields,\n },\n { token },\n );\n childGroupUsers = await Promise.all(childGroups.items.map(mapEntity));\n }\n\n return [...groupUsers, ...childGroupUsers.flat(2)].filter(\n ref => !excluded.includes(ref),\n );\n }\n\n if (entity.relations?.length) {\n const ownerRef = entity.relations.find(\n relation => relation.type === RELATION_OWNED_BY,\n )?.targetRef;\n\n if (!ownerRef) {\n return [];\n }\n\n if (isUserEntityRef(ownerRef)) {\n if (excluded.includes(ownerRef)) {\n return [];\n }\n return [ownerRef];\n }\n\n const owner = await catalogClient.getEntityByRef(ownerRef, { token });\n return mapEntity(owner);\n }\n\n return [];\n };\n\n for (const entity of entities) {\n const u = await mapEntity(entity);\n users.push(...u);\n }\n\n return [...new Set(users)].filter(Boolean);\n};\n"],"names":["parseEntityRef","stringifyEntityRef","isUserEntity","isGroupEntity","RELATION_HAS_MEMBER","RELATION_PARENT_OF","RELATION_OWNED_BY"],"mappings":"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"}
1
+ {"version":3,"file":"getUsersForEntityRef.cjs.js","sources":["../../src/service/getUsersForEntityRef.ts"],"sourcesContent":["/*\n * Copyright 2024 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 */\n\nimport {\n Entity,\n isGroupEntity,\n isUserEntity,\n parseEntityRef,\n RELATION_HAS_MEMBER,\n RELATION_OWNED_BY,\n RELATION_PARENT_OF,\n stringifyEntityRef,\n} from '@backstage/catalog-model';\nimport { AuthService } from '@backstage/backend-plugin-api';\nimport { CatalogService } from '@backstage/plugin-catalog-node';\n\nconst isUserEntityRef = (ref: string) =>\n parseEntityRef(ref).kind.toLocaleLowerCase() === 'user';\n\n// Partitions array of entity references to two arrays; user entity refs and other entity refs\nconst partitionEntityRefs = (refs: string[]): string[][] =>\n refs.reduce(\n ([userEntityRefs, otherEntityRefs]: string[][], ref: string) => {\n return isUserEntityRef(ref)\n ? [[...userEntityRefs, ref], otherEntityRefs]\n : [userEntityRefs, [...otherEntityRefs, ref]];\n },\n [[], []],\n );\n\nexport const getUsersForEntityRef = async (\n entityRef: string | string[] | null,\n excludeEntityRefs: string | string[],\n options: {\n auth: AuthService;\n catalog: CatalogService;\n },\n): Promise<string[]> => {\n const { auth, catalog } = options;\n\n if (entityRef === null) {\n return [];\n }\n\n const excluded = Array.isArray(excludeEntityRefs)\n ? excludeEntityRefs\n : [excludeEntityRefs];\n\n const refsArr = Array.isArray(entityRef) ? entityRef : [entityRef];\n const [userEntityRefs, otherEntityRefs] = partitionEntityRefs(refsArr);\n const users: string[] = userEntityRefs.filter(ref => !excluded.includes(ref));\n const entityRefs = otherEntityRefs.filter(ref => !excluded.includes(ref));\n\n const fields = ['kind', 'metadata.name', 'metadata.namespace', 'relations'];\n let entities: Array<Entity | undefined> = [];\n if (entityRefs.length > 0) {\n const fetchedEntities = await catalog.getEntitiesByRefs(\n {\n entityRefs,\n fields,\n },\n { credentials: await auth.getOwnServiceCredentials() },\n );\n entities = fetchedEntities.items;\n }\n\n const mapEntity = async (entity: Entity | undefined): Promise<string[]> => {\n if (!entity) {\n return [];\n }\n\n const currentEntityRef = stringifyEntityRef(entity);\n if (excluded.includes(currentEntityRef)) {\n return [];\n }\n\n if (isUserEntity(entity)) {\n return [currentEntityRef];\n }\n\n if (isGroupEntity(entity)) {\n if (!entity.relations?.length) {\n return [];\n }\n\n const groupUsers = entity.relations\n .filter(\n relation =>\n relation.type === RELATION_HAS_MEMBER &&\n isUserEntityRef(relation.targetRef),\n )\n .map(r => r.targetRef);\n\n const childGroupRefs = entity.relations\n .filter(relation => relation.type === RELATION_PARENT_OF)\n .map(r => r.targetRef);\n\n let childGroupUsers: string[][] = [];\n if (childGroupRefs.length > 0) {\n const childGroups = await catalog.getEntitiesByRefs(\n {\n entityRefs: childGroupRefs,\n fields,\n },\n { credentials: await auth.getOwnServiceCredentials() },\n );\n childGroupUsers = await Promise.all(childGroups.items.map(mapEntity));\n }\n\n return [...groupUsers, ...childGroupUsers.flat(2)].filter(\n ref => !excluded.includes(ref),\n );\n }\n\n if (entity.relations?.length) {\n const ownerRef = entity.relations.find(\n relation => relation.type === RELATION_OWNED_BY,\n )?.targetRef;\n\n if (!ownerRef) {\n return [];\n }\n\n if (isUserEntityRef(ownerRef)) {\n if (excluded.includes(ownerRef)) {\n return [];\n }\n return [ownerRef];\n }\n\n const owner = await catalog.getEntityByRef(ownerRef, {\n credentials: await auth.getOwnServiceCredentials(),\n });\n return mapEntity(owner);\n }\n\n return [];\n };\n\n for (const entity of entities) {\n const u = await mapEntity(entity);\n users.push(...u);\n }\n\n return [...new Set(users)].filter(Boolean);\n};\n"],"names":["parseEntityRef","stringifyEntityRef","isUserEntity","isGroupEntity","RELATION_HAS_MEMBER","RELATION_PARENT_OF","RELATION_OWNED_BY"],"mappings":"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"}
@@ -22,7 +22,7 @@ async function createRouter(options) {
22
22
  const {
23
23
  config: config$1,
24
24
  logger,
25
- database,
25
+ store,
26
26
  auth,
27
27
  httpAuth,
28
28
  userInfo,
@@ -31,7 +31,6 @@ async function createRouter(options) {
31
31
  signals
32
32
  } = options;
33
33
  const WEB_NOTIFICATION_CHANNEL = "Web";
34
- const store = await DatabaseNotificationsStore.DatabaseNotificationsStore.create({ database });
35
34
  const frontendBaseUrl = config$1.getString("app.baseUrl");
36
35
  const concurrencyLimit = config$1.getOptionalNumber("notifications.concurrencyLimit") ?? 10;
37
36
  const throttleInterval = config$1.has("notifications.throttleInterval") ? types.durationToMilliseconds(
@@ -484,7 +483,7 @@ async function createRouter(options) {
484
483
  users = await getUsersForEntityRef.getUsersForEntityRef(
485
484
  entityRef,
486
485
  recipients.excludeEntityRef ?? [],
487
- { auth, catalogClient: catalog }
486
+ { auth, catalog }
488
487
  );
489
488
  } catch (e) {
490
489
  throw new errors.InputError("Failed to resolve notification receivers", e);
@@ -1 +1 @@
1
- {"version":3,"file":"router.cjs.js","sources":["../../src/service/router.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 */\n\nimport express, { Request, Response } from 'express';\nimport Router from 'express-promise-router';\nimport {\n DatabaseNotificationsStore,\n normalizeSeverity,\n NotificationGetOptions,\n TopicGetOptions,\n} from '../database';\nimport { v4 as uuid } from 'uuid';\nimport { CatalogApi } from '@backstage/catalog-client';\nimport {\n NotificationProcessor,\n NotificationSendOptions,\n} from '@backstage/plugin-notifications-node';\nimport { InputError, NotFoundError } from '@backstage/errors';\nimport {\n AuthService,\n DatabaseService,\n HttpAuthService,\n LoggerService,\n UserInfoService,\n} from '@backstage/backend-plugin-api';\nimport { SignalsService } from '@backstage/plugin-signals-node';\nimport {\n ChannelSetting,\n isNotificationsEnabledFor,\n NewNotificationSignal,\n Notification,\n NotificationReadSignal,\n NotificationSettings,\n notificationSeverities,\n NotificationStatus,\n OriginSetting,\n} from '@backstage/plugin-notifications-common';\nimport { parseEntityOrderFieldParams } from './parseEntityOrderFieldParams';\nimport { getUsersForEntityRef } from './getUsersForEntityRef';\nimport { Config, readDurationFromConfig } from '@backstage/config';\nimport { durationToMilliseconds } from '@backstage/types';\nimport pThrottle from 'p-throttle';\n\n/** @internal */\nexport interface RouterOptions {\n logger: LoggerService;\n config: Config;\n database: DatabaseService;\n auth: AuthService;\n httpAuth: HttpAuthService;\n userInfo: UserInfoService;\n signals?: SignalsService;\n catalog: CatalogApi;\n processors?: NotificationProcessor[];\n}\n\n/** @internal */\nexport async function createRouter(\n options: RouterOptions,\n): Promise<express.Router> {\n const {\n config,\n logger,\n database,\n auth,\n httpAuth,\n userInfo,\n catalog,\n processors = [],\n signals,\n } = options;\n\n const WEB_NOTIFICATION_CHANNEL = 'Web';\n const store = await DatabaseNotificationsStore.create({ database });\n const frontendBaseUrl = config.getString('app.baseUrl');\n const concurrencyLimit =\n config.getOptionalNumber('notifications.concurrencyLimit') ?? 10;\n const throttleInterval = config.has('notifications.throttleInterval')\n ? durationToMilliseconds(\n readDurationFromConfig(config, {\n key: 'notifications.throttleInterval',\n }),\n )\n : 50;\n const throttle = pThrottle({\n limit: concurrencyLimit,\n interval: throttleInterval,\n });\n\n const getUser = async (req: Request<unknown>) => {\n const credentials = await httpAuth.credentials(req, { allow: ['user'] });\n const info = await userInfo.getUserInfo(credentials);\n return info.userEntityRef;\n };\n\n const getTopicSettings = (\n topic: any,\n existingOrigin: OriginSetting | undefined,\n defaultEnabled: boolean,\n ) => {\n const existingTopic = existingOrigin?.topics?.find(\n t => t.id === topic.topic,\n );\n return {\n id: topic.topic,\n enabled: existingTopic ? existingTopic.enabled : defaultEnabled,\n };\n };\n\n const getOriginSettings = (\n originId: string,\n existingChannel: ChannelSetting | undefined,\n topics: { origin: string; topic: string }[],\n ) => {\n const existingOrigin = existingChannel?.origins.find(\n o => o.id === originId,\n );\n const defaultEnabled = existingOrigin ? existingOrigin.enabled : true;\n return {\n id: originId,\n enabled: defaultEnabled,\n topics: topics\n .filter(t => t.origin === originId)\n .map(t => getTopicSettings(t, existingOrigin, defaultEnabled)),\n };\n };\n\n const getNotificationChannels = () => {\n return [WEB_NOTIFICATION_CHANNEL, ...processors.map(p => p.getName())];\n };\n\n const getChannelSettings = (\n channelId: string,\n settings: NotificationSettings,\n origins: string[],\n topics: { origin: string; topic: string }[],\n ) => {\n const existingChannel = settings.channels.find(c => c.id === channelId);\n if (existingChannel) {\n return existingChannel;\n }\n return {\n id: channelId,\n origins: origins.map(originId =>\n getOriginSettings(originId, existingChannel, topics),\n ),\n };\n };\n\n const getNotificationSettings = async (user: string) => {\n const { origins } = await store.getUserNotificationOrigins({ user });\n const { topics } = await store.getUserNotificationTopics({ user });\n const settings = await store.getNotificationSettings({ user });\n const channels = getNotificationChannels();\n\n return {\n channels: channels.map(channelId =>\n getChannelSettings(channelId, settings, origins, topics),\n ),\n };\n };\n\n const isNotificationsEnabled = async (opts: {\n user: string;\n channel: string;\n origin: string;\n topic: string | null;\n }) => {\n const settings = await getNotificationSettings(opts.user);\n return isNotificationsEnabledFor(\n settings,\n opts.channel,\n opts.origin,\n opts.topic,\n );\n };\n\n const filterProcessors = async (\n notification:\n | Notification\n | ({ origin: string; user: null } & NotificationSendOptions),\n ) => {\n const result: NotificationProcessor[] = [];\n const { payload, user, origin } = notification;\n\n for (const processor of processors) {\n if (user) {\n const enabled = await isNotificationsEnabled({\n user,\n origin,\n channel: processor.getName(),\n topic: payload.topic ?? null,\n });\n if (!enabled) {\n continue;\n }\n }\n\n if (processor.getNotificationFilters) {\n const filters = processor.getNotificationFilters();\n if (filters.minSeverity) {\n if (\n notificationSeverities.indexOf(payload.severity ?? 'normal') >\n notificationSeverities.indexOf(filters.minSeverity)\n ) {\n continue;\n }\n }\n\n if (filters.maxSeverity) {\n if (\n notificationSeverities.indexOf(payload.severity ?? 'normal') <\n notificationSeverities.indexOf(filters.maxSeverity)\n ) {\n continue;\n }\n }\n\n if (filters.excludedTopics && payload.topic) {\n if (filters.excludedTopics.includes(payload.topic)) {\n continue;\n }\n }\n }\n result.push(processor);\n }\n\n return result;\n };\n\n const processOptions = async (\n opts: NotificationSendOptions,\n origin: string,\n ): Promise<NotificationSendOptions> => {\n const filtered = await filterProcessors({ ...opts, origin, user: null });\n let ret = opts;\n for (const processor of filtered) {\n try {\n ret = processor.processOptions\n ? await processor.processOptions(ret)\n : ret;\n } catch (e) {\n logger.error(\n `Error while processing notification options with ${processor.getName()}: ${e}`,\n );\n }\n }\n return ret;\n };\n\n const preProcessNotification = async (\n notification: Notification,\n opts: NotificationSendOptions,\n ) => {\n const filtered = await filterProcessors(notification);\n let ret = notification;\n for (const processor of filtered) {\n try {\n ret = processor.preProcess\n ? await processor.preProcess(ret, opts)\n : ret;\n } catch (e) {\n logger.error(\n `Error while pre processing notification with ${processor.getName()}: ${e}`,\n );\n }\n }\n return ret;\n };\n\n const postProcessNotification = async (\n notification: Notification,\n opts: NotificationSendOptions,\n ) => {\n const filtered = await filterProcessors(notification);\n for (const processor of filtered) {\n if (processor.postProcess) {\n try {\n await processor.postProcess(notification, opts);\n } catch (e) {\n logger.error(\n `Error while post processing notification with ${processor.getName()}: ${e}`,\n );\n }\n }\n }\n };\n\n const validateLink = (link: string) => {\n const stripLeadingSlash = (s: string) => s.replace(/^\\//, '');\n const ensureTrailingSlash = (s: string) => s.replace(/\\/?$/, '/');\n const url = new URL(\n stripLeadingSlash(link),\n ensureTrailingSlash(frontendBaseUrl),\n );\n if (url.protocol !== 'https:' && url.protocol !== 'http:') {\n throw new Error('Only HTTP/HTTPS links are allowed');\n }\n };\n\n const appendCommonOptions = (\n req: Request,\n opts: NotificationGetOptions | TopicGetOptions,\n ) => {\n if (req.query.search) {\n opts.search = req.query.search.toString();\n }\n if (req.query.read === 'true') {\n opts.read = true;\n } else if (req.query.read === 'false') {\n opts.read = false;\n // or keep undefined\n }\n\n if (req.query.saved === 'true') {\n opts.saved = true;\n } else if (req.query.saved === 'false') {\n opts.saved = false;\n // or keep undefined\n }\n if (req.query.createdAfter) {\n const sinceEpoch = Date.parse(String(req.query.createdAfter));\n if (isNaN(sinceEpoch)) {\n throw new InputError('Unexpected date format');\n }\n opts.createdAfter = new Date(sinceEpoch);\n }\n if (req.query.minimumSeverity) {\n opts.minimumSeverity = normalizeSeverity(\n req.query.minimumSeverity.toString(),\n );\n }\n };\n\n // TODO: Move to use OpenAPI router instead\n const router = Router();\n router.use(express.json());\n\n const listNotificationsHandler = async (req: Request, res: Response) => {\n const user = await getUser(req);\n const opts: NotificationGetOptions = {\n user: user,\n };\n if (req.query.offset) {\n opts.offset = Number.parseInt(req.query.offset.toString(), 10);\n }\n if (req.query.limit) {\n opts.limit = Number.parseInt(req.query.limit.toString(), 10);\n }\n if (req.query.orderField) {\n opts.orderField = parseEntityOrderFieldParams(req.query);\n }\n\n if (req.query.topic) {\n opts.topic = req.query.topic.toString();\n }\n\n appendCommonOptions(req, opts);\n\n const [notifications, totalCount] = await Promise.all([\n store.getNotifications(opts),\n store.getNotificationsCount(opts),\n ]);\n res.json({\n totalCount,\n notifications,\n });\n };\n\n router.get('/', listNotificationsHandler); // Deprecated endpoint\n router.get('/notifications', listNotificationsHandler);\n\n router.get('/status', async (req: Request<any, NotificationStatus>, res) => {\n const user = await getUser(req);\n const status = await store.getStatus({ user });\n res.json(status);\n });\n\n router.get(\n '/settings',\n async (req: Request<any, NotificationSettings>, res) => {\n const user = await getUser(req);\n const response = await getNotificationSettings(user);\n res.json(response);\n },\n );\n\n router.post(\n '/settings',\n async (\n req: Request<any, NotificationSettings, NotificationSettings>,\n res,\n ) => {\n const user = await getUser(req);\n const channels = getNotificationChannels();\n const settings: NotificationSettings = req.body;\n if (settings.channels.some(c => !channels.includes(c.id))) {\n throw new InputError('Invalid channel');\n }\n await store.saveNotificationSettings({ user, settings });\n const response = await getNotificationSettings(user);\n res.json(response);\n },\n );\n\n const getNotificationHandler = async (req: Request, res: Response) => {\n const user = await getUser(req);\n const opts: NotificationGetOptions = {\n user: user,\n limit: 1,\n ids: [req.params.id],\n };\n const notifications = await store.getNotifications(opts);\n if (notifications.length !== 1) {\n throw new NotFoundError('Not found');\n }\n res.json(notifications[0]);\n };\n\n // Get topics\n const listTopicsHandler = async (req: Request, res: Response) => {\n const user = await getUser(req);\n const opts: TopicGetOptions = {\n user: user,\n };\n\n appendCommonOptions(req, opts);\n\n const topics = await store.getTopics(opts);\n res.json(topics);\n };\n\n router.get('/topics', listTopicsHandler);\n\n // Make sure this is the last \"GET\" handler\n router.get('/:id', getNotificationHandler); // Deprecated endpoint\n router.get('/notifications/:id', getNotificationHandler);\n\n const updateNotificationsHandler = async (req: Request, res: Response) => {\n const user = await getUser(req);\n const { ids, read, saved } = req.body;\n if (!ids || !Array.isArray(ids)) {\n throw new InputError();\n }\n\n if (read === true) {\n await store.markRead({ user, ids });\n\n if (signals) {\n await signals.publish<NotificationReadSignal>({\n recipients: { type: 'user', entityRef: [user] },\n message: { action: 'notification_read', notification_ids: ids },\n channel: 'notifications',\n });\n }\n } else if (read === false) {\n await store.markUnread({ user: user, ids });\n\n if (signals) {\n await signals.publish<NotificationReadSignal>({\n recipients: { type: 'user', entityRef: [user] },\n message: { action: 'notification_unread', notification_ids: ids },\n channel: 'notifications',\n });\n }\n }\n\n if (saved === true) {\n await store.markSaved({ user: user, ids });\n } else if (saved === false) {\n await store.markUnsaved({ user: user, ids });\n }\n\n const notifications = await store.getNotifications({ ids, user: user });\n res.json(notifications);\n };\n\n router.post('/update', updateNotificationsHandler); // Deprecated endpoint\n router.post('/notifications/update', updateNotificationsHandler);\n\n const sendBroadcastNotification = async (\n baseNotification: Omit<Notification, 'user' | 'id'>,\n opts: NotificationSendOptions,\n origin: string,\n ) => {\n const { scope } = opts.payload;\n const broadcastNotification = {\n ...baseNotification,\n user: null,\n id: uuid(),\n };\n const notification = await preProcessNotification(\n broadcastNotification,\n opts,\n );\n let existingNotification;\n if (scope) {\n existingNotification = await store.getExistingScopeBroadcast({\n scope,\n origin,\n });\n }\n\n let ret = notification;\n if (existingNotification) {\n const restored = await store.restoreExistingNotification({\n id: existingNotification.id,\n notification: { ...notification, user: '' },\n });\n ret = restored ?? notification;\n } else {\n await store.saveBroadcast(notification);\n }\n\n if (signals) {\n await signals.publish<NewNotificationSignal>({\n recipients: { type: 'broadcast' },\n message: {\n action: 'new_notification',\n notification_id: ret.id,\n },\n channel: 'notifications',\n });\n }\n postProcessNotification(ret, opts);\n return notification;\n };\n\n const sendUserNotification = async (\n baseNotification: Omit<Notification, 'user' | 'id'>,\n user: string,\n opts: NotificationSendOptions,\n origin: string,\n scope?: string,\n ): Promise<Notification | undefined> => {\n const userNotification = {\n ...baseNotification,\n id: uuid(),\n user,\n };\n const notification = await preProcessNotification(userNotification, opts);\n\n const enabled = await isNotificationsEnabled({\n user,\n channel: WEB_NOTIFICATION_CHANNEL,\n origin: userNotification.origin,\n topic: userNotification.payload.topic ?? null,\n });\n\n let ret = notification;\n\n if (!enabled) {\n postProcessNotification(ret, opts);\n return undefined;\n }\n\n let existingNotification;\n if (scope) {\n existingNotification = await store.getExistingScopeNotification({\n user,\n scope,\n origin,\n });\n }\n\n if (existingNotification) {\n const restored = await store.restoreExistingNotification({\n id: existingNotification.id,\n notification,\n });\n ret = restored ?? notification;\n } else {\n await store.saveNotification(notification);\n }\n\n if (signals) {\n await signals.publish<NewNotificationSignal>({\n recipients: { type: 'user', entityRef: [user] },\n message: {\n action: 'new_notification',\n notification_id: ret.id,\n },\n channel: 'notifications',\n });\n }\n postProcessNotification(ret, opts);\n return ret;\n };\n\n const sendUserNotifications = async (\n baseNotification: Omit<Notification, 'user' | 'id'>,\n users: string[],\n opts: NotificationSendOptions,\n origin: string,\n ): Promise<Notification[]> => {\n const { scope } = opts.payload;\n const uniqueUsers = [...new Set(users)];\n const throttled = throttle((user: string) =>\n sendUserNotification(baseNotification, user, opts, origin, scope),\n );\n const sent = await Promise.all(uniqueUsers.map(user => throttled(user)));\n return sent.filter(n => n !== undefined);\n };\n\n const createNotificationHandler = async (\n req: Request<any, Notification[], NotificationSendOptions>,\n res: Response,\n ) => {\n const credentials = await httpAuth.credentials(req, {\n allow: ['service'],\n });\n\n const origin = credentials.principal.subject;\n const opts = await processOptions(req.body, origin);\n const { recipients, payload } = opts;\n const { title, link } = payload;\n const notifications: Notification[] = [];\n let users = [];\n\n if (!recipients || !title) {\n const missing = [\n !title ? 'title' : null,\n !recipients ? 'recipients' : null,\n ].filter(Boolean);\n const err = `Invalid notification request received: missing ${missing.join(\n ', ',\n )}`;\n throw new InputError(err);\n }\n\n if (link) {\n try {\n validateLink(link);\n } catch (e) {\n throw new InputError('Invalid link provided', e);\n }\n }\n\n const baseNotification = {\n payload: {\n ...payload,\n severity: payload.severity ?? 'normal',\n },\n origin,\n created: new Date(),\n };\n\n if (recipients.type === 'broadcast') {\n const broadcast = await sendBroadcastNotification(\n baseNotification,\n opts,\n origin,\n );\n notifications.push(broadcast);\n } else if (recipients.type === 'entity') {\n const entityRef = recipients.entityRef;\n\n try {\n users = await getUsersForEntityRef(\n entityRef,\n recipients.excludeEntityRef ?? [],\n { auth, catalogClient: catalog },\n );\n } catch (e) {\n throw new InputError('Failed to resolve notification receivers', e);\n }\n\n const userNotifications = await sendUserNotifications(\n baseNotification,\n users,\n opts,\n origin,\n );\n notifications.push(...userNotifications);\n } else {\n throw new InputError(\n `Invalid recipients type, please use either 'broadcast' or 'entity'`,\n );\n }\n\n res.json(notifications);\n };\n\n // Add new notification\n router.post('/', createNotificationHandler);\n router.post('/notifications', createNotificationHandler);\n\n return router;\n}\n"],"names":["config","DatabaseNotificationsStore","durationToMilliseconds","readDurationFromConfig","pThrottle","isNotificationsEnabledFor","notificationSeverities","InputError","normalizeSeverity","Router","express","parseEntityOrderFieldParams","NotFoundError","uuid","getUsersForEntityRef"],"mappings":"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"}
1
+ {"version":3,"file":"router.cjs.js","sources":["../../src/service/router.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 */\n\nimport express, { Request, Response } from 'express';\nimport Router from 'express-promise-router';\nimport {\n normalizeSeverity,\n NotificationGetOptions,\n NotificationsStore,\n TopicGetOptions,\n} from '../database';\nimport { v4 as uuid } from 'uuid';\nimport { CatalogService } from '@backstage/plugin-catalog-node';\nimport {\n NotificationProcessor,\n NotificationSendOptions,\n} from '@backstage/plugin-notifications-node';\nimport { InputError, NotFoundError } from '@backstage/errors';\nimport {\n AuthService,\n HttpAuthService,\n LoggerService,\n UserInfoService,\n} from '@backstage/backend-plugin-api';\nimport { SignalsService } from '@backstage/plugin-signals-node';\nimport {\n ChannelSetting,\n isNotificationsEnabledFor,\n NewNotificationSignal,\n Notification,\n NotificationReadSignal,\n NotificationSettings,\n notificationSeverities,\n NotificationStatus,\n OriginSetting,\n} from '@backstage/plugin-notifications-common';\nimport { parseEntityOrderFieldParams } from './parseEntityOrderFieldParams';\nimport { getUsersForEntityRef } from './getUsersForEntityRef';\nimport { Config, readDurationFromConfig } from '@backstage/config';\nimport { durationToMilliseconds } from '@backstage/types';\nimport pThrottle from 'p-throttle';\n\n/** @internal */\nexport interface RouterOptions {\n logger: LoggerService;\n config: Config;\n store: NotificationsStore;\n auth: AuthService;\n httpAuth: HttpAuthService;\n userInfo: UserInfoService;\n signals?: SignalsService;\n catalog: CatalogService;\n processors?: NotificationProcessor[];\n}\n\n/** @internal */\nexport async function createRouter(\n options: RouterOptions,\n): Promise<express.Router> {\n const {\n config,\n logger,\n store,\n auth,\n httpAuth,\n userInfo,\n catalog,\n processors = [],\n signals,\n } = options;\n\n const WEB_NOTIFICATION_CHANNEL = 'Web';\n const frontendBaseUrl = config.getString('app.baseUrl');\n const concurrencyLimit =\n config.getOptionalNumber('notifications.concurrencyLimit') ?? 10;\n const throttleInterval = config.has('notifications.throttleInterval')\n ? durationToMilliseconds(\n readDurationFromConfig(config, {\n key: 'notifications.throttleInterval',\n }),\n )\n : 50;\n const throttle = pThrottle({\n limit: concurrencyLimit,\n interval: throttleInterval,\n });\n\n const getUser = async (req: Request<unknown>) => {\n const credentials = await httpAuth.credentials(req, { allow: ['user'] });\n const info = await userInfo.getUserInfo(credentials);\n return info.userEntityRef;\n };\n\n const getTopicSettings = (\n topic: any,\n existingOrigin: OriginSetting | undefined,\n defaultEnabled: boolean,\n ) => {\n const existingTopic = existingOrigin?.topics?.find(\n t => t.id === topic.topic,\n );\n return {\n id: topic.topic,\n enabled: existingTopic ? existingTopic.enabled : defaultEnabled,\n };\n };\n\n const getOriginSettings = (\n originId: string,\n existingChannel: ChannelSetting | undefined,\n topics: { origin: string; topic: string }[],\n ) => {\n const existingOrigin = existingChannel?.origins.find(\n o => o.id === originId,\n );\n const defaultEnabled = existingOrigin ? existingOrigin.enabled : true;\n return {\n id: originId,\n enabled: defaultEnabled,\n topics: topics\n .filter(t => t.origin === originId)\n .map(t => getTopicSettings(t, existingOrigin, defaultEnabled)),\n };\n };\n\n const getNotificationChannels = () => {\n return [WEB_NOTIFICATION_CHANNEL, ...processors.map(p => p.getName())];\n };\n\n const getChannelSettings = (\n channelId: string,\n settings: NotificationSettings,\n origins: string[],\n topics: { origin: string; topic: string }[],\n ) => {\n const existingChannel = settings.channels.find(c => c.id === channelId);\n if (existingChannel) {\n return existingChannel;\n }\n return {\n id: channelId,\n origins: origins.map(originId =>\n getOriginSettings(originId, existingChannel, topics),\n ),\n };\n };\n\n const getNotificationSettings = async (user: string) => {\n const { origins } = await store.getUserNotificationOrigins({ user });\n const { topics } = await store.getUserNotificationTopics({ user });\n const settings = await store.getNotificationSettings({ user });\n const channels = getNotificationChannels();\n\n return {\n channels: channels.map(channelId =>\n getChannelSettings(channelId, settings, origins, topics),\n ),\n };\n };\n\n const isNotificationsEnabled = async (opts: {\n user: string;\n channel: string;\n origin: string;\n topic: string | null;\n }) => {\n const settings = await getNotificationSettings(opts.user);\n return isNotificationsEnabledFor(\n settings,\n opts.channel,\n opts.origin,\n opts.topic,\n );\n };\n\n const filterProcessors = async (\n notification:\n | Notification\n | ({ origin: string; user: null } & NotificationSendOptions),\n ) => {\n const result: NotificationProcessor[] = [];\n const { payload, user, origin } = notification;\n\n for (const processor of processors) {\n if (user) {\n const enabled = await isNotificationsEnabled({\n user,\n origin,\n channel: processor.getName(),\n topic: payload.topic ?? null,\n });\n if (!enabled) {\n continue;\n }\n }\n\n if (processor.getNotificationFilters) {\n const filters = processor.getNotificationFilters();\n if (filters.minSeverity) {\n if (\n notificationSeverities.indexOf(payload.severity ?? 'normal') >\n notificationSeverities.indexOf(filters.minSeverity)\n ) {\n continue;\n }\n }\n\n if (filters.maxSeverity) {\n if (\n notificationSeverities.indexOf(payload.severity ?? 'normal') <\n notificationSeverities.indexOf(filters.maxSeverity)\n ) {\n continue;\n }\n }\n\n if (filters.excludedTopics && payload.topic) {\n if (filters.excludedTopics.includes(payload.topic)) {\n continue;\n }\n }\n }\n result.push(processor);\n }\n\n return result;\n };\n\n const processOptions = async (\n opts: NotificationSendOptions,\n origin: string,\n ): Promise<NotificationSendOptions> => {\n const filtered = await filterProcessors({ ...opts, origin, user: null });\n let ret = opts;\n for (const processor of filtered) {\n try {\n ret = processor.processOptions\n ? await processor.processOptions(ret)\n : ret;\n } catch (e) {\n logger.error(\n `Error while processing notification options with ${processor.getName()}: ${e}`,\n );\n }\n }\n return ret;\n };\n\n const preProcessNotification = async (\n notification: Notification,\n opts: NotificationSendOptions,\n ) => {\n const filtered = await filterProcessors(notification);\n let ret = notification;\n for (const processor of filtered) {\n try {\n ret = processor.preProcess\n ? await processor.preProcess(ret, opts)\n : ret;\n } catch (e) {\n logger.error(\n `Error while pre processing notification with ${processor.getName()}: ${e}`,\n );\n }\n }\n return ret;\n };\n\n const postProcessNotification = async (\n notification: Notification,\n opts: NotificationSendOptions,\n ) => {\n const filtered = await filterProcessors(notification);\n for (const processor of filtered) {\n if (processor.postProcess) {\n try {\n await processor.postProcess(notification, opts);\n } catch (e) {\n logger.error(\n `Error while post processing notification with ${processor.getName()}: ${e}`,\n );\n }\n }\n }\n };\n\n const validateLink = (link: string) => {\n const stripLeadingSlash = (s: string) => s.replace(/^\\//, '');\n const ensureTrailingSlash = (s: string) => s.replace(/\\/?$/, '/');\n const url = new URL(\n stripLeadingSlash(link),\n ensureTrailingSlash(frontendBaseUrl),\n );\n if (url.protocol !== 'https:' && url.protocol !== 'http:') {\n throw new Error('Only HTTP/HTTPS links are allowed');\n }\n };\n\n const appendCommonOptions = (\n req: Request,\n opts: NotificationGetOptions | TopicGetOptions,\n ) => {\n if (req.query.search) {\n opts.search = req.query.search.toString();\n }\n if (req.query.read === 'true') {\n opts.read = true;\n } else if (req.query.read === 'false') {\n opts.read = false;\n // or keep undefined\n }\n\n if (req.query.saved === 'true') {\n opts.saved = true;\n } else if (req.query.saved === 'false') {\n opts.saved = false;\n // or keep undefined\n }\n if (req.query.createdAfter) {\n const sinceEpoch = Date.parse(String(req.query.createdAfter));\n if (isNaN(sinceEpoch)) {\n throw new InputError('Unexpected date format');\n }\n opts.createdAfter = new Date(sinceEpoch);\n }\n if (req.query.minimumSeverity) {\n opts.minimumSeverity = normalizeSeverity(\n req.query.minimumSeverity.toString(),\n );\n }\n };\n\n // TODO: Move to use OpenAPI router instead\n const router = Router();\n router.use(express.json());\n\n const listNotificationsHandler = async (req: Request, res: Response) => {\n const user = await getUser(req);\n const opts: NotificationGetOptions = {\n user: user,\n };\n if (req.query.offset) {\n opts.offset = Number.parseInt(req.query.offset.toString(), 10);\n }\n if (req.query.limit) {\n opts.limit = Number.parseInt(req.query.limit.toString(), 10);\n }\n if (req.query.orderField) {\n opts.orderField = parseEntityOrderFieldParams(req.query);\n }\n\n if (req.query.topic) {\n opts.topic = req.query.topic.toString();\n }\n\n appendCommonOptions(req, opts);\n\n const [notifications, totalCount] = await Promise.all([\n store.getNotifications(opts),\n store.getNotificationsCount(opts),\n ]);\n res.json({\n totalCount,\n notifications,\n });\n };\n\n router.get('/', listNotificationsHandler); // Deprecated endpoint\n router.get('/notifications', listNotificationsHandler);\n\n router.get('/status', async (req: Request<any, NotificationStatus>, res) => {\n const user = await getUser(req);\n const status = await store.getStatus({ user });\n res.json(status);\n });\n\n router.get(\n '/settings',\n async (req: Request<any, NotificationSettings>, res) => {\n const user = await getUser(req);\n const response = await getNotificationSettings(user);\n res.json(response);\n },\n );\n\n router.post(\n '/settings',\n async (\n req: Request<any, NotificationSettings, NotificationSettings>,\n res,\n ) => {\n const user = await getUser(req);\n const channels = getNotificationChannels();\n const settings: NotificationSettings = req.body;\n if (settings.channels.some(c => !channels.includes(c.id))) {\n throw new InputError('Invalid channel');\n }\n await store.saveNotificationSettings({ user, settings });\n const response = await getNotificationSettings(user);\n res.json(response);\n },\n );\n\n const getNotificationHandler = async (req: Request, res: Response) => {\n const user = await getUser(req);\n const opts: NotificationGetOptions = {\n user: user,\n limit: 1,\n ids: [req.params.id],\n };\n const notifications = await store.getNotifications(opts);\n if (notifications.length !== 1) {\n throw new NotFoundError('Not found');\n }\n res.json(notifications[0]);\n };\n\n // Get topics\n const listTopicsHandler = async (req: Request, res: Response) => {\n const user = await getUser(req);\n const opts: TopicGetOptions = {\n user: user,\n };\n\n appendCommonOptions(req, opts);\n\n const topics = await store.getTopics(opts);\n res.json(topics);\n };\n\n router.get('/topics', listTopicsHandler);\n\n // Make sure this is the last \"GET\" handler\n router.get('/:id', getNotificationHandler); // Deprecated endpoint\n router.get('/notifications/:id', getNotificationHandler);\n\n const updateNotificationsHandler = async (req: Request, res: Response) => {\n const user = await getUser(req);\n const { ids, read, saved } = req.body;\n if (!ids || !Array.isArray(ids)) {\n throw new InputError();\n }\n\n if (read === true) {\n await store.markRead({ user, ids });\n\n if (signals) {\n await signals.publish<NotificationReadSignal>({\n recipients: { type: 'user', entityRef: [user] },\n message: { action: 'notification_read', notification_ids: ids },\n channel: 'notifications',\n });\n }\n } else if (read === false) {\n await store.markUnread({ user: user, ids });\n\n if (signals) {\n await signals.publish<NotificationReadSignal>({\n recipients: { type: 'user', entityRef: [user] },\n message: { action: 'notification_unread', notification_ids: ids },\n channel: 'notifications',\n });\n }\n }\n\n if (saved === true) {\n await store.markSaved({ user: user, ids });\n } else if (saved === false) {\n await store.markUnsaved({ user: user, ids });\n }\n\n const notifications = await store.getNotifications({ ids, user: user });\n res.json(notifications);\n };\n\n router.post('/update', updateNotificationsHandler); // Deprecated endpoint\n router.post('/notifications/update', updateNotificationsHandler);\n\n const sendBroadcastNotification = async (\n baseNotification: Omit<Notification, 'user' | 'id'>,\n opts: NotificationSendOptions,\n origin: string,\n ) => {\n const { scope } = opts.payload;\n const broadcastNotification = {\n ...baseNotification,\n user: null,\n id: uuid(),\n };\n const notification = await preProcessNotification(\n broadcastNotification,\n opts,\n );\n let existingNotification;\n if (scope) {\n existingNotification = await store.getExistingScopeBroadcast({\n scope,\n origin,\n });\n }\n\n let ret = notification;\n if (existingNotification) {\n const restored = await store.restoreExistingNotification({\n id: existingNotification.id,\n notification: { ...notification, user: '' },\n });\n ret = restored ?? notification;\n } else {\n await store.saveBroadcast(notification);\n }\n\n if (signals) {\n await signals.publish<NewNotificationSignal>({\n recipients: { type: 'broadcast' },\n message: {\n action: 'new_notification',\n notification_id: ret.id,\n },\n channel: 'notifications',\n });\n }\n postProcessNotification(ret, opts);\n return notification;\n };\n\n const sendUserNotification = async (\n baseNotification: Omit<Notification, 'user' | 'id'>,\n user: string,\n opts: NotificationSendOptions,\n origin: string,\n scope?: string,\n ): Promise<Notification | undefined> => {\n const userNotification = {\n ...baseNotification,\n id: uuid(),\n user,\n };\n const notification = await preProcessNotification(userNotification, opts);\n\n const enabled = await isNotificationsEnabled({\n user,\n channel: WEB_NOTIFICATION_CHANNEL,\n origin: userNotification.origin,\n topic: userNotification.payload.topic ?? null,\n });\n\n let ret = notification;\n\n if (!enabled) {\n postProcessNotification(ret, opts);\n return undefined;\n }\n\n let existingNotification;\n if (scope) {\n existingNotification = await store.getExistingScopeNotification({\n user,\n scope,\n origin,\n });\n }\n\n if (existingNotification) {\n const restored = await store.restoreExistingNotification({\n id: existingNotification.id,\n notification,\n });\n ret = restored ?? notification;\n } else {\n await store.saveNotification(notification);\n }\n\n if (signals) {\n await signals.publish<NewNotificationSignal>({\n recipients: { type: 'user', entityRef: [user] },\n message: {\n action: 'new_notification',\n notification_id: ret.id,\n },\n channel: 'notifications',\n });\n }\n postProcessNotification(ret, opts);\n return ret;\n };\n\n const sendUserNotifications = async (\n baseNotification: Omit<Notification, 'user' | 'id'>,\n users: string[],\n opts: NotificationSendOptions,\n origin: string,\n ): Promise<Notification[]> => {\n const { scope } = opts.payload;\n const uniqueUsers = [...new Set(users)];\n const throttled = throttle((user: string) =>\n sendUserNotification(baseNotification, user, opts, origin, scope),\n );\n const sent = await Promise.all(uniqueUsers.map(user => throttled(user)));\n return sent.filter(n => n !== undefined);\n };\n\n const createNotificationHandler = async (\n req: Request<any, Notification[], NotificationSendOptions>,\n res: Response,\n ) => {\n const credentials = await httpAuth.credentials(req, {\n allow: ['service'],\n });\n\n const origin = credentials.principal.subject;\n const opts = await processOptions(req.body, origin);\n const { recipients, payload } = opts;\n const { title, link } = payload;\n const notifications: Notification[] = [];\n let users = [];\n\n if (!recipients || !title) {\n const missing = [\n !title ? 'title' : null,\n !recipients ? 'recipients' : null,\n ].filter(Boolean);\n const err = `Invalid notification request received: missing ${missing.join(\n ', ',\n )}`;\n throw new InputError(err);\n }\n\n if (link) {\n try {\n validateLink(link);\n } catch (e) {\n throw new InputError('Invalid link provided', e);\n }\n }\n\n const baseNotification = {\n payload: {\n ...payload,\n severity: payload.severity ?? 'normal',\n },\n origin,\n created: new Date(),\n };\n\n if (recipients.type === 'broadcast') {\n const broadcast = await sendBroadcastNotification(\n baseNotification,\n opts,\n origin,\n );\n notifications.push(broadcast);\n } else if (recipients.type === 'entity') {\n const entityRef = recipients.entityRef;\n\n try {\n users = await getUsersForEntityRef(\n entityRef,\n recipients.excludeEntityRef ?? [],\n { auth, catalog },\n );\n } catch (e) {\n throw new InputError('Failed to resolve notification receivers', e);\n }\n\n const userNotifications = await sendUserNotifications(\n baseNotification,\n users,\n opts,\n origin,\n );\n notifications.push(...userNotifications);\n } else {\n throw new InputError(\n `Invalid recipients type, please use either 'broadcast' or 'entity'`,\n );\n }\n\n res.json(notifications);\n };\n\n // Add new notification\n router.post('/', createNotificationHandler);\n router.post('/notifications', createNotificationHandler);\n\n return router;\n}\n"],"names":["config","durationToMilliseconds","readDurationFromConfig","pThrottle","isNotificationsEnabledFor","notificationSeverities","InputError","normalizeSeverity","Router","express","parseEntityOrderFieldParams","NotFoundError","uuid","getUsersForEntityRef"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@backstage/plugin-notifications-backend",
3
- "version": "0.5.7-next.1",
3
+ "version": "0.5.7",
4
4
  "backstage": {
5
5
  "role": "backend-plugin",
6
6
  "pluginId": "notifications",
@@ -42,18 +42,17 @@
42
42
  "test": "backstage-cli package test"
43
43
  },
44
44
  "dependencies": {
45
- "@backstage/backend-plugin-api": "1.4.0-next.1",
46
- "@backstage/catalog-client": "1.10.1-next.0",
47
- "@backstage/catalog-model": "1.7.4",
48
- "@backstage/config": "1.3.2",
49
- "@backstage/errors": "1.2.7",
50
- "@backstage/plugin-auth-node": "0.6.4-next.1",
51
- "@backstage/plugin-catalog-node": "1.17.1-next.1",
52
- "@backstage/plugin-events-node": "0.4.12-next.1",
53
- "@backstage/plugin-notifications-common": "0.0.9-next.0",
54
- "@backstage/plugin-notifications-node": "0.2.16-next.1",
55
- "@backstage/plugin-signals-node": "0.1.21-next.1",
56
- "@backstage/types": "1.2.1",
45
+ "@backstage/backend-plugin-api": "^1.4.0",
46
+ "@backstage/catalog-model": "^1.7.4",
47
+ "@backstage/config": "^1.3.2",
48
+ "@backstage/errors": "^1.2.7",
49
+ "@backstage/plugin-auth-node": "^0.6.4",
50
+ "@backstage/plugin-catalog-node": "^1.17.1",
51
+ "@backstage/plugin-events-node": "^0.4.12",
52
+ "@backstage/plugin-notifications-common": "^0.0.9",
53
+ "@backstage/plugin-notifications-node": "^0.2.16",
54
+ "@backstage/plugin-signals-node": "^0.1.21",
55
+ "@backstage/types": "^1.2.1",
57
56
  "express": "^4.17.1",
58
57
  "express-promise-router": "^4.1.0",
59
58
  "knex": "^3.0.0",
@@ -63,13 +62,13 @@
63
62
  "yn": "^4.0.0"
64
63
  },
65
64
  "devDependencies": {
66
- "@backstage/backend-defaults": "0.10.1-next.1",
67
- "@backstage/backend-test-utils": "1.6.0-next.1",
68
- "@backstage/cli": "0.32.2-next.0",
69
- "@backstage/plugin-auth-backend": "0.25.1-next.1",
70
- "@backstage/plugin-auth-backend-module-guest-provider": "0.2.9-next.1",
71
- "@backstage/plugin-events-backend": "0.5.3-next.1",
72
- "@backstage/plugin-signals-backend": "0.3.5-next.1",
65
+ "@backstage/backend-defaults": "^0.11.0",
66
+ "@backstage/backend-test-utils": "^1.6.0",
67
+ "@backstage/cli": "^0.33.0",
68
+ "@backstage/plugin-auth-backend": "^0.25.1",
69
+ "@backstage/plugin-auth-backend-module-guest-provider": "^0.2.9",
70
+ "@backstage/plugin-events-backend": "^0.5.3",
71
+ "@backstage/plugin-signals-backend": "^0.3.5",
73
72
  "@types/express": "^4.17.6",
74
73
  "@types/supertest": "^2.0.8",
75
74
  "msw": "^1.0.0",