{"_id":"@batzionrotman123/plugin-notifications-backend","name":"@batzionrotman123/plugin-notifications-backend","dist-tags":{"latest":"1.0.0-redhat-0001"},"versions":{"1.0.0-redhat-0001":{"name":"@batzionrotman123/plugin-notifications-backend","version":"1.0.0-redhat-0001","main":"src/index.ts","types":"src/index.ts","license":"Apache-2.0","publishConfig":{"access":"public","main":"dist/index.cjs.js","types":"dist/index.d.ts"},"backstage":{"role":"backend-plugin"},"exports":{".":"./src/index.ts","./alpha":"./src/alpha.ts","./package.json":"./package.json"},"typesVersions":{"*":{"alpha":["src/alpha.ts"],"package.json":["package.json"]}},"scripts":{"start":"backstage-cli package start","build":"backstage-cli package build","lint":"backstage-cli package lint","test":"backstage-cli package test --passWithNoTests --coverage","clean":"backstage-cli package clean","prepack":"backstage-cli package prepack","postpack":"backstage-cli package postpack","postversion":"yarn run export-dynamic","tsc":"tsc","openapi":"./scripts/openapi.sh","export-dynamic":"janus-cli package export-dynamic-plugin"},"configSchema":"config.d.ts","dependencies":{"@backstage/backend-common":"^0.21.3","@backstage/backend-openapi-utils":"^0.1.6","@backstage/catalog-client":"^1.6.0","@backstage/config":"^1.1.1","@backstage/errors":"^1.2.3","@backstage/backend-plugin-api":"^0.6.13","@backstage/backend-dynamic-feature-service":"^0.2.3","@backstage/plugin-auth-node":"^0.4.8","@backstage/plugin-permission-common":"^0.7.12","@backstage/plugin-permission-node":"^0.7.24","@backstage/plugin-scaffolder-node":"^0.3.3","ajv-formats":"^2.1.1","express":"^4.18.2","express-promise-router":"^4.1.1","knex":"^3.0.0","lodash":"^4.17.21","node-fetch":"^3.3.2","openapi":"^1.0.1","openapi-backend":"^5.10.5","yn":"^4.0.0"},"devDependencies":{"@backstage/backend-test-utils":"0.3.3","@backstage/catalog-model":"1.4.4","@backstage/cli":"0.25.2","@types/express":"*","@types/supertest":"2.0.16","@janus-idp/cli":"1.7.5","js-yaml-cli":"0.6.0","knex-mock-client":"2.0.1","msw":"1.3.2","openapicmd":"2.1.0","supertest":"6.3.3"},"_id":"@batzionrotman123/plugin-notifications-backend@1.0.0-redhat-0001","gitHead":"2b4faadd43df8c740444d83a7efac955cf443922","description":"This Backstage backend plugin provides REST API endpoint for the notifications.","_nodeVersion":"18.19.1","_npmVersion":"10.2.4","dist":{"integrity":"sha512-SR5wNVBa1BldRs5b4BDp6n1BlnaznPyim8B/MBsgIox187TRnZUBBjQpx8Oq7Atjza0VSVHAMqz82CJQzYktug==","shasum":"14ebcd1fed8b27cc306ce27f3d50e7f1e616cc57","tarball":"https://registry.npmjs.org/@batzionrotman123/plugin-notifications-backend/-/plugin-notifications-backend-1.0.0-redhat-0001.tgz","fileCount":24,"unpackedSize":281359,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEMCH2M/YM1d3QOo7YYLbhuO0LaIqIpIYXSnVZ2bHJgu+9UCIA56wYjK1WtTFgFDdA6WdcIo3E7AiI5TG3EahWV5Y6f3"}]},"_npmUser":{"name":"batzionrotman123","email":"batzionrotman@gmail.com"},"directories":{},"maintainers":[{"name":"batzionrotman123","email":"batzionrotman@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/plugin-notifications-backend_1.0.0-redhat-0001_1711886272979_0.40714429803442664"},"_hasShrinkwrap":false}},"time":{"created":"2024-03-31T11:57:52.892Z","1.0.0-redhat-0001":"2024-03-31T11:57:53.166Z","modified":"2024-03-31T11:57:53.422Z"},"maintainers":[{"name":"batzionrotman123","email":"batzionrotman@gmail.com"}],"description":"This Backstage backend plugin provides REST API endpoint for the notifications.","license":"Apache-2.0","readme":"# Notifications\n\nThis Backstage backend plugin provides REST API endpoint for the notifications.\n\nIt's backed by a relational database, so far tested with PostgreSQL.\n\n## Deploying as a dynamic plugin\n\nThe notifications backend plugin can be loaded either as a static or a dynamic plugin.\n\nTo install it as a dynamic plugin, please follow instructions here: https://github.com/janus-idp/backstage-showcase/blob/main/showcase-docs/dynamic-plugins.md#installing-a-dynamic-plugin-package-in-the-showcase\n\nTo install it as a static plugin, several steps are required as described below for both the legacy backend and the new backend system.\n\nIn any case, do not miss the info about configuration and especially about creating entities [in the Catalog as described below](#important-user-entities-in-catalog).\n\n## Getting started\n\nThe plugin uses a relational database to persist messages, it has been tested with the SQLite and PostgreSQL.\n\nUpon the backend's plugin start, the `backstage_plugin_notifications` database and its tables are created automatically.\n\n### Optional: PostgreSQL setup\n\n**To use the Backstage's default SQLite database, no specific configuration is needed.**\n\nThe following steps describe requirements for PostgreSQL:\n\n- Install [PostgresSQL DB](https://www.postgresql.org/download/)\n- Configure Postgres for tcp/ip\n  Open Postgres conf file for editing:\n\n```bash\nsudo vi /var/lib/pgsql/data/pg_hba.conf\n```\n\nAdd this line:\n\n```bash\nhost   all             postgres       127.0.0.1/32                          password\n```\n\n- Start Postgres server:\n\n```bash\nsudo systemctl enable --now postgresql.service\n```\n\n#### Backstage configuration for PostgreSQL\n\nIf PostgreSQL is used, additional configuration in the `app-config.yaml` file or `app-config.local.yaml` file is needed. Example:\n\n```yaml\nbackend:\n  database:\n    client: pg\n    connection:\n      host: 127.0.0.1\n      port: 5432\n      user: postgres\n      password: your_secret\n    knexConfig:\n      pool:\n        min: 3\n        max: 12\n        acquireTimeoutMillis: 60000\n        idleTimeoutMillis: 60000\n  cache:\n    store: memory\n```\n\n## Deploy as a static plugin\n\n### Add NPM dependency\n\n```bash\ncd packages/backend\nyarn add @janus-idp/plugin-notifications-backend\n```\n\n### Add the backend-plugin for the legacy backend\n\nCreate a `packages/backend/src/plugins/notifications.ts` file with the following content:\n\n```ts title=\"packages/backend/src/plugins/notifications.ts\"\nimport { CatalogClient } from '@backstage/catalog-client';\n\nimport { Router } from 'express';\n\nimport { createRouter } from '@janus-idp/plugin-notifications-backend';\n\nimport { PluginEnvironment } from '../types';\n\nexport default async function createPlugin(\n  env: PluginEnvironment,\n): Promise<Router> {\n  return await createRouter({\n    identity: env.identity,\n    logger: env.logger,\n    permissions: env.permissions,\n    tokenManager: env.tokenManager,\n    database: env.database,\n    discovery: env.discovery,\n    config: env.config,\n  });\n}\n```\n\nIn the `packages/backend/src/index.ts`, add the following:\n\n```ts title=\"packages/backend/src/index.ts\"\nimport notifications from './plugins/notifications';\n...\n// Existing code for reference:\nconst apiRouter = Router();\n...\n// New code:\nconst notificationsEnv = useHotMemoize(module, () =>\n  createEnv('notifications'),\n);\napiRouter.use('/notifications', await notifications(notificationsEnv));\n```\n\n### Installing the plugin for the new backend system\n\nAdd the following code to the `packages/backend/src/index.ts`:\n\n```ts title=\"packages/backend/src/index.ts\"\nconst backend = createBackend();\n\n/* highlight-add-next-line */\nbackend.add(import('@janus-idp/backstage-plugin-notifications-backend/alpha'));\n\nbackend.start();\n```\n\n## Configuration\n\n### Optional: Plugin configuration\n\nIf you have issues to create valid JWT tokens by an external caller, use following option to bypass the service-to-service configuration for them:\n\n```yaml\nnotifications:\n  # Workaround for issues with external caller JWT token creation.\n  # When following config option is not provided and the request \"authentication\" header is missing, the request is ALLOWED by default\n  # When following option is present, the request must contain either a valid JWT token or that provided shared secret in the \"notifications-secret\" header\n  externalCallerSecret: your-secret-token-shared-with-external-services\n```\n\nWe suggest using HTTPS to help prevent leaking the shared secret.\n\nExample Request:\n\n```bash\ncurl -X POST http://localhost:7007/api/notifications/notifications -H \"Content-Type: application/json\" -H \"notifications-secret: your-secret-token-shared-with-external-services\" -d '{\"title\":\"my-title\",\"origin\":\"my-origin\",\"message\":\"message one\",\"topic\":\"my-topic\"}'\n\n```\n\nNotes:\n\n- The `externalCallerSecret` is an workaround, exclusive use of JWT tokens will probably be required in the future.\n- Sharing the same shared secret with the \"auth.secret\" option is not recommended.\n\n## Authentication\n\nPlease refer to https://backstage.io/docs/auth/ to set-up authentication.\n\nThe Notifications flows are based on the identity of the user.\n\nAll `targetUsers`, `targetGroups`` or signed-in users receiving notifications must have corresponding entities created in the Catalog.\nRefer to https://backstage.io/docs/auth/identity-resolver for details.\n\nFor the purpose of development, there is a `users.yaml` file listing example data to create a Guest user entity.\n\n## Authorization\n\nEvery service endpoint is guarded by a permission check, enabled by default.\n\nIt is up to particular deployment to provide corresponding permission policies based on https://backstage.io/docs/permissions/writing-a-policy. To register your permission policies, refer to https://backstage.io/docs/permissions/getting-started#integrating-the-permission-framework-with-your-backstage-instance.\n\n### Service-to-service and External Calls\n\nThe notifications-backend is expected to be called by frontend plugins (including the Notifications frontend plugin), other backend plugins or external services.\n\nTo configure those two flows, refer to:\n\n- https://backstage.io/docs/auth/service-to-service-auth.\n- https://backstage.io/docs/auth/service-to-service-auth#usage-in-external-callers\n\n### Important: User entities in Catalog\n\n_The notifications require target users or groups (as receivers) to be listed in the Catalog._\n\nAs an example how to do it, add following to the config:\n\n```yaml\ncatalog:\n  import:\n    entityFilename: catalog-info.yaml\n    pullRequestBranchName: backstage-integration\n  rules:\n    # *** Here is a new change:\n    - allow: [Component, System, API, Resource, Location, User, Group]\n  locations:\n    # Local example data, file locations are relative to the backend process, typically `packages/backend`\n    - type: file\n      # *** Here is a new change, refers to a file stored in the root of the Backstage:\n      target: ../../plugins/notifications-backend/users.yaml\n```\n\n## REST API\n\nSee `src/openapi.yaml` for full OpenAPI spec.\n\n### Posting a notification\n\nA notification without target users or groups is considered a system notification. That means it is intended for all users (listed among Updates in the UI).\n\nRequest (User message and then system message):\n\n```bash\ncurl -X POST http://localhost:7007/api/notifications/notifications -H \"Content-Type: application/json\" -d '{\"title\": \"My message title\", \"message\": \"I have nothing to say\", \"origin\": \"my-origin\", \"topic\":\"my topic\", \"targetUsers\": [\"default/guest\"], \"actions\": [{\"title\": \"my-title\", \"url\": \"http://foo.bar\"}, {\"title\": \"another action\", \"url\": \"https://foo.foo.bar\"}]}'\n```\n\nOptionally add `-H \"Authorization: Bearer eyJh.....` with a valid JWT token if the service-to-service authorization is enabled (see above).\n\nResponse:\n\n```json\n{ \"msgid\": \"2daac6ff-3aaa-420d-b755-d94e54248310\" }\n```\n\n### Get notifications\n\nPage number starts at '1'. Page number '0' along with page size '0' means no paging.\nUser parameter is mandatory because it is needed for message status and filtering (read/unread).\n\nQuery parameters:\n\n- `pageSize`. 0 means no paging.\n- `pageNumber`. first page is 1. 0 means no paging.\n- `orderBy`.\n- `orderByDirec`. asc/desc\n- `containsText`. filter title and message containing this text (case insensitive)\n- `createdAfter`. fetch notifications created after this point in time\n- `messageScope`. all/user/system. fetch notifications intended for specific user or system notifications or both\n- `read`. true/false (read/unread)\n\nRequest:\n\n```bash\ncurl 'http://localhost:7007/api/notifications/notifications?read=false&pageNumber=0&pageSize=0'\n```\n\nResponse:\n\n```json\n[\n  {\n    \"id\": \"2daac6ff-3aaa-420d-b755-d94e54248310\",\n    \"created\": \"2023-10-30T13:48:34.931Z\",\n    \"isSystem\": false,\n    \"readByUser\": false,\n    \"origin\": \"my-origin\",\n    \"title\": \"My title\",\n    \"message\": \"I have nothing to tell\",\n    \"topic\": \"my-topic\",\n    \"actions\": []\n  }\n]\n```\n\n### Get count of notifications\n\nUser parameter is mandatory because it is needed for filtering (read/unread).\n\n**Important: Logged-in user:**\n\nThe query requires a signed-in user whose entity is listed in the Catalog.\nWith this condition is met, the HTTP `Authorization` header contains a JWT token with the user's identity.\n\nOptionally add `-H \"Authorization: Bearer eyJh.....` with a valid JWT token to the `curl` commands bellow.\n\nQuery parameters:\n\n- `containsText`. filter title and message containing this text (case insensitive)\n- `createdAfter`. fetch notifications created after this point in time\n- `messageScope`. all/user/system. fetch notifications intended for specific user or system notifications or both\n- `read`. true/false (read/unread)\n\nRequest:\n\n```bash\ncurl http://localhost:7007/api/notifications/notifications/count\n```\n\nResponse:\n\n```json\n{ \"count\": \"1\" }\n```\n\n### Set notification as read/unread\n\nRequest:\n\n```bash\ncurl -X PUT 'http://localhost:7007/api/notifications/notifications/read?messageId=48bbf896-4b7c-4b68-a446-246b6a801000&read=true'\n```\n\nResponse: A HTTP Status Code\n\n## Building a client for the API\n\nWe supply an Open API spec YAML file at `src/openapi.yaml`.\n","readmeFilename":"README.md"}