From e9f44ac764858b9d2dcfab4d158df67786bccbc2 Mon Sep 17 00:00:00 2001 From: Robert Rosman Date: Wed, 27 Mar 2024 05:58:19 +0100 Subject: [PATCH 01/10] feat: add service-worker --- backend/app/urls.py | 2 ++ backend/app/views/web_views.py | 6 ++++++ frontend/src/mount.js | 8 ++++++++ frontend/static/js/service-worker.js | 18 ++++++++++++++++++ 4 files changed, 34 insertions(+) create mode 100644 frontend/static/js/service-worker.js diff --git a/backend/app/urls.py b/backend/app/urls.py index a4d7b9fd2..87560118d 100644 --- a/backend/app/urls.py +++ b/backend/app/urls.py @@ -44,6 +44,8 @@ path('publictimelapses/', RedirectView.as_view(url='/ent_pub/publictimelapses/', permanent=True), name='publictimelapse_list'), path('slack_oauth_callback/', web_views.slack_oauth_callback, name='slack_oauth_callback'), path('printer_events/', web_views.printer_events), + + path('service-worker.js', web_views.service_worker), # tunnel v2 redirect and page with iframe re_path( diff --git a/backend/app/views/web_views.py b/backend/app/views/web_views.py index 49901fae1..1d909ca8f 100644 --- a/backend/app/views/web_views.py +++ b/backend/app/views/web_views.py @@ -267,3 +267,9 @@ def health_check(request): User.objects.all()[:1] cache.printer_pic_get(0) return HttpResponse('Okay') + +# Service worker must be located at root to get the correct scope, therefor served as a web view +def service_worker(request): + sw_path = f'{settings.BASE_DIR}/static_build/js/service-worker.js' + response = HttpResponse(open(sw_path).read(), content_type='application/javascript') + return response \ No newline at end of file diff --git a/frontend/src/mount.js b/frontend/src/mount.js index 4265ee31a..159366b50 100644 --- a/frontend/src/mount.js +++ b/frontend/src/mount.js @@ -109,3 +109,11 @@ export default (router, components) => { }, }) } + +if ('serviceWorker' in navigator) { + window.addEventListener('load', function() { + navigator.serviceWorker.register('/service-worker.js').catch(err => { + console.error('ServiceWorker registration failed: ', err); + }); + }); +} \ No newline at end of file diff --git a/frontend/static/js/service-worker.js b/frontend/static/js/service-worker.js new file mode 100644 index 000000000..63fd736d4 --- /dev/null +++ b/frontend/static/js/service-worker.js @@ -0,0 +1,18 @@ +self.addEventListener("push", (event) => { + if (!(self.Notification && self.Notification.permission === "granted")) { + return; + } + let data = event.data.json(); + const image = "https://www.obico.io/wwwimg/favicon.png"; + const options = { + body: data.message, + icon: image, + }; + self.registration.showNotification(data.title, options); +}); + +// TODO +// self.addEventListener("notificationClick", (event) => { +// event.notification.close(); +// event.waitUntil(self.clients.openWindow("https://app.obico.io")); +// }); From 643282c456ae08a490b4ef971de0ee7598a81f78 Mon Sep 17 00:00:00 2001 From: Robert Rosman Date: Wed, 27 Mar 2024 06:08:57 +0100 Subject: [PATCH 02/10] wip: add Browser plugin, for now only working with test messages --- backend/Pipfile | 1 + .../notifications/plugins/browser/__init__.py | 102 ++++++++ backend/requirements.txt | 1 + docker-compose.yml | 3 + dotenv.example | 10 + frontend/src/notifications/plugins.js | 4 + .../notifications/plugins/BrowserPlugin.vue | 233 ++++++++++++++++++ 7 files changed, 354 insertions(+) create mode 100644 backend/notifications/plugins/browser/__init__.py create mode 100644 frontend/src/notifications/plugins/BrowserPlugin.vue diff --git a/backend/Pipfile b/backend/Pipfile index c5d784dfc..ba2ed94e5 100644 --- a/backend/Pipfile +++ b/backend/Pipfile @@ -55,6 +55,7 @@ numpy = "1.26.0" django-debug-toolbar = "*" inotify-simple = "*" Twisted = {extras = ["tls", "http2"], version = "*" } +pywebpush = "2.0.0" [dev-packages] diff --git a/backend/notifications/plugins/browser/__init__.py b/backend/notifications/plugins/browser/__init__.py new file mode 100644 index 000000000..20e08551f --- /dev/null +++ b/backend/notifications/plugins/browser/__init__.py @@ -0,0 +1,102 @@ +from typing import Dict, Optional, Any +import logging +import io +import os +from enum import IntEnum +from rest_framework.serializers import ValidationError +from pywebpush import webpush, WebPushException +import json +from lib import site as site + +from notifications.plugin import ( + BaseNotificationPlugin, + FailureAlertContext, + PrinterNotificationContext, + TestMessageContext, +) + +LOGGER = logging.getLogger(__name__) + + +class BrowserException(Exception): + pass + +class BrowserNotificationPlugin(BaseNotificationPlugin): + + def validate_config(self, data: Dict) -> Dict: + if 'subscriptions' in data: + return {'subscriptions': data['subscriptions']} + raise ValidationError('subscriptions are missing from config') + + def env_vars(self) -> Dict: + return { + 'VAPID_PUBLIC_KEY': { + 'is_required': True, + 'is_set': 'VAPID_PUBLIC_KEY' in os.environ, + 'value': os.environ.get('VAPID_PUBLIC_KEY'), + }, + } + + def i(self, s: str) -> str: + return f"{s}" + + def b(self, s: str): + return f"{s}" + + def u(self, s: str): + return f"{s}" + + def send_notification( + self, + config: Dict, + title: str, + message: str, + priority: Optional[BrowserPriority] = None, + file_content: Optional[bytes] = None, + timeout: float = 5.0, + ) -> None: + vapid_subject = os.environ.get('VAPID_SUBJECT') + + for subscription in config['subscriptions']: + try: + webpush( + subscription_info={ + "endpoint": subscription['endpoint'], + "keys": subscription['keys'], + }, + data=json.dumps({ + "title": title, + "message": message, + }), + vapid_private_key=os.environ.get('VAPID_PRIVATE_KEY'), + vapid_claims={ + "sub": f'mailto:{vapid_subject}', + } + ) + except WebPushException as ex: + LOGGER.warn("Failed to send browser push notification: {}", repr(ex)) + # Mozilla returns additional information in the body of the response. + if ex.response and ex.response.json(): + extra = ex.response.json() + LOGGER.warn("Remote service replied with a {}:{}, {}", + extra.code, + extra.errno, + extra.message + ) + + def send_failure_alert(self, context: FailureAlertContext) -> None: + # TODO + + def send_printer_notification(self, context: PrinterNotificationContext) -> None: + # TODO + + def send_test_message(self, context: TestMessageContext) -> None: + self.send_notification( + config=context.config, + title='Test Notification', + message='It works!', + ) + + +def __load_plugin__(): + return BrowserNotificationPlugin() diff --git a/backend/requirements.txt b/backend/requirements.txt index 19a4feece..2065266bb 100644 --- a/backend/requirements.txt +++ b/backend/requirements.txt @@ -116,6 +116,7 @@ python-dateutil==2.8.2 ; python_version >= '2.7' and python_version not in '3.0, python-magic==0.4.27 ; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4' python3-openid==3.2.0 pytz==2023.3.post1 +pywebpush==2.0.0 redis==4.6.0 requests==2.31.0 ; python_version >= '3.7' requests-oauthlib==1.3.1 ; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3' diff --git a/docker-compose.yml b/docker-compose.yml index da2c041b7..0b5d32004 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -37,6 +37,9 @@ x-web-defaults: &web-defaults PUSHOVER_APP_TOKEN: '${PUSHOVER_APP_TOKEN-}' SLACK_CLIENT_ID: '${SLACK_CLIENT_ID-}' SLACK_CLIENT_SECRET: '${SLACK_CLIENT_SECRET-}' + VAPID_PUBLIC_KEY: '${VAPID_PUBLIC_KEY-}' + VAPID_PRIVATE_KEY: '${VAPID_PRIVATE_KEY-}' + VAPID_SUBJECT: '${VAPID_SUBJECT-}' DJANGO_SECRET_KEY: '${DJANGO_SECRET_KEY-}' VERSION: diff --git a/dotenv.example b/dotenv.example index 0b8c6f9b4..6a411023c 100644 --- a/dotenv.example +++ b/dotenv.example @@ -65,3 +65,13 @@ # https://api.slack.com/legacy/oauth # SLACK_CLIENT_SECRET= + +# VAPID_PUBLIC_KEY= + +# VAPID_PRIVATE_KEY= +# Vapid keys are used to encrypt Browser notifications. Keys can be generated with this command: `npx web-push generate-vapid-keys`. +# Both public and private keys are required for the plugin to work. +# NOTE: Replacing the keys with fresh ones will make notification to all previously registered devices stop working. + +# VAPID_SUBJECT= +# Vapid subject is a valid email address that will be used as "sender". `mailto:` will be added by the plugin itself. \ No newline at end of file diff --git a/frontend/src/notifications/plugins.js b/frontend/src/notifications/plugins.js index 4db9764e7..e01836b6c 100644 --- a/frontend/src/notifications/plugins.js +++ b/frontend/src/notifications/plugins.js @@ -31,4 +31,8 @@ export default { displayName: 'Webhook', componentName: 'WebhookPlugin', }, + browser: { + displayName: 'Browser', + componentName: 'BrowserPlugin', + } } diff --git a/frontend/src/notifications/plugins/BrowserPlugin.vue b/frontend/src/notifications/plugins/BrowserPlugin.vue new file mode 100644 index 000000000..85acc69a3 --- /dev/null +++ b/frontend/src/notifications/plugins/BrowserPlugin.vue @@ -0,0 +1,233 @@ + + + + + From c87e248f1e0a5e0bbeaf7d8030916ce2d1648a76 Mon Sep 17 00:00:00 2001 From: Robert Rosman Date: Wed, 27 Mar 2024 07:40:59 +0100 Subject: [PATCH 03/10] refactor: make supported a computed property --- frontend/src/notifications/plugins/BrowserPlugin.vue | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/frontend/src/notifications/plugins/BrowserPlugin.vue b/frontend/src/notifications/plugins/BrowserPlugin.vue index 85acc69a3..abda3156e 100644 --- a/frontend/src/notifications/plugins/BrowserPlugin.vue +++ b/frontend/src/notifications/plugins/BrowserPlugin.vue @@ -86,7 +86,6 @@ export default { }, data: () => ({ - supported: false, denied: false, subscription: null, name: '', @@ -104,15 +103,15 @@ export default { subscribed() { return this.configSubscriptions.some(s => s.endpoint === this.subscription?.endpoint) - } + }, + supported() { + return !!window && "Notification" in window + } }, mounted() { - if (!!window && "Notification" in window) { - this.supported = true; - } - else if (Notification?.permission === "denied") { + if (Notification?.permission === "denied") { this.denied = true; } this.configSubscriptions = this.notificationChannel.channelInfo?.config.subscriptions ?? [] From 2646661589190272d6ab3048382a7d78e5a1e039 Mon Sep 17 00:00:00 2001 From: Robert Rosman Date: Wed, 27 Mar 2024 07:52:21 +0100 Subject: [PATCH 04/10] fix: cleanup unused code --- backend/notifications/plugins/browser/__init__.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/backend/notifications/plugins/browser/__init__.py b/backend/notifications/plugins/browser/__init__.py index 20e08551f..22c56db6a 100644 --- a/backend/notifications/plugins/browser/__init__.py +++ b/backend/notifications/plugins/browser/__init__.py @@ -51,7 +51,6 @@ def send_notification( config: Dict, title: str, message: str, - priority: Optional[BrowserPriority] = None, file_content: Optional[bytes] = None, timeout: float = 5.0, ) -> None: @@ -85,10 +84,10 @@ def send_notification( ) def send_failure_alert(self, context: FailureAlertContext) -> None: - # TODO + LOGGER.warn("Not implemented yet") def send_printer_notification(self, context: PrinterNotificationContext) -> None: - # TODO + LOGGER.warn("Not implemented yet") def send_test_message(self, context: TestMessageContext) -> None: self.send_notification( From a61c1944f404b8eef30717a330bd1127fdda9c44 Mon Sep 17 00:00:00 2001 From: Robert Rosman Date: Wed, 27 Mar 2024 07:52:39 +0100 Subject: [PATCH 05/10] fix: stop relying on configInfo in mounted --- .../notifications/plugins/BrowserPlugin.vue | 23 +++++++++++-------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/frontend/src/notifications/plugins/BrowserPlugin.vue b/frontend/src/notifications/plugins/BrowserPlugin.vue index abda3156e..6b933563b 100644 --- a/frontend/src/notifications/plugins/BrowserPlugin.vue +++ b/frontend/src/notifications/plugins/BrowserPlugin.vue @@ -89,7 +89,6 @@ export default { denied: false, subscription: null, name: '', - configSubscriptions: [] }), computed: { @@ -107,6 +106,10 @@ export default { supported() { return !!window && "Notification" in window + }, + + configSubscriptions() { + return this.notificationChannel.channelInfo?.config.subscriptions ?? [] } }, @@ -114,7 +117,6 @@ export default { if (Notification?.permission === "denied") { this.denied = true; } - this.configSubscriptions = this.notificationChannel.channelInfo?.config.subscriptions ?? [] navigator.serviceWorker.getRegistration().then(registration => { registration.pushManager.getSubscription().then(subscription => this.subscription = subscription); }); @@ -136,8 +138,10 @@ export default { applicationServerKey: this.vapidPublicKey, }); } - this.configSubscriptions.push({ ...this.subscription.toJSON(), name: this.name }) - this.updateConfig() + this.updateConfig([ + ...this.configSubscriptions, + { ...this.subscription.toJSON(), name: this.name } + ]) } else { this.denied = true @@ -155,29 +159,28 @@ export default { }) .then(async (confirmed) => { if (confirmed) { - this.configSubscriptions = this.configSubscriptions.filter(subscription => subscription.endpoint !== device.endpoint) - this.updateConfig() + this.updateConfig(this.configSubscriptions.filter(subscription => subscription.endpoint !== device.endpoint)) } }) }, - updateConfig() { + updateConfig(subscriptions) { if (!this.notificationChannel.channelInfo) { this.$emit('createNotificationChannel', { section: this.notificationChannel, config: { - subscriptions: this.configSubscriptions + subscriptions } }) } - else if (this.configSubscriptions.length === 0) { + else if (subscriptions.length === 0) { this.$emit('deleteNotificationChannel', this.notificationChannel) } else { this.$emit('updateNotificationChannel', { section: this.notificationChannel, propNames: ['config'], - propValues: [{ subscriptions: this.configSubscriptions }], + propValues: [{ subscriptions }], }) } }, From 0948683fcc5e2de7e23505d473ef13f1478c390d Mon Sep 17 00:00:00 2001 From: Robert Rosman Date: Wed, 27 Mar 2024 08:10:13 +0100 Subject: [PATCH 06/10] style: make remove button transparent --- frontend/src/notifications/plugins/BrowserPlugin.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/notifications/plugins/BrowserPlugin.vue b/frontend/src/notifications/plugins/BrowserPlugin.vue index 6b933563b..87b6d7db0 100644 --- a/frontend/src/notifications/plugins/BrowserPlugin.vue +++ b/frontend/src/notifications/plugins/BrowserPlugin.vue @@ -43,7 +43,7 @@ {{ device.name }} - + From 6c1d1d317314ffeb35cfa72b5537b2deaab994e8 Mon Sep 17 00:00:00 2001 From: Robert Rosman Date: Wed, 27 Mar 2024 08:19:17 +0100 Subject: [PATCH 07/10] feat: autodetect browser and os --- frontend/package.json | 1 + frontend/src/notifications/plugins/BrowserPlugin.vue | 5 +++++ frontend/yarn.lock | 5 +++++ 3 files changed, 11 insertions(+) diff --git a/frontend/package.json b/frontend/package.json index d92d6156c..1971a2f8b 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -16,6 +16,7 @@ "@fortawesome/vue-fontawesome": "^2.0.10", "axios": "^1.3.3", "bootstrap-vue": "^2.15.0", + "bowser": "^2.11.0", "core-js": "^3.6.4", "d3": "^7.8.2", "filesize": "^3.6.1", diff --git a/frontend/src/notifications/plugins/BrowserPlugin.vue b/frontend/src/notifications/plugins/BrowserPlugin.vue index 87b6d7db0..2dc06b8dd 100644 --- a/frontend/src/notifications/plugins/BrowserPlugin.vue +++ b/frontend/src/notifications/plugins/BrowserPlugin.vue @@ -62,6 +62,7 @@ import NotificationChannelTemplate from '@src/components/user-preferences/notifications/NotificationChannelTemplate.vue' import axios from 'axios' import urls from '@config/server-urls' +import Bowser from 'bowser' export default { name: 'BrowserPlugin', @@ -120,6 +121,10 @@ export default { navigator.serviceWorker.getRegistration().then(registration => { registration.pushManager.getSubscription().then(subscription => this.subscription = subscription); }); + const {browser, os} = Bowser.parse(window.navigator.userAgent) + if (browser?.name && os?.name) { + this.name = `${browser.name} on ${os.name}` + } }, methods: { diff --git a/frontend/yarn.lock b/frontend/yarn.lock index e2919b358..c907564c7 100644 --- a/frontend/yarn.lock +++ b/frontend/yarn.lock @@ -2253,6 +2253,11 @@ bootstrap@^4.6.1: resolved "https://registry.yarnpkg.com/bootstrap/-/bootstrap-4.6.2.tgz#8e0cd61611728a5bf65a3a2b8d6ff6c77d5d7479" integrity sha512-51Bbp/Uxr9aTuy6ca/8FbFloBUJZLHwnhTcnjIeRn2suQWsWzcuJhGjKDB5eppVte/8oCdOL3VuwxvZDUggwGQ== +bowser@^2.11.0: + version "2.11.0" + resolved "https://registry.yarnpkg.com/bowser/-/bowser-2.11.0.tgz#5ca3c35757a7aa5771500c70a73a9f91ef420a8f" + integrity sha512-AlcaJBi/pqqJBIQ8U9Mcpc9i8Aqxn88Skv5d+xBX006BY5u8N3mGLHa5Lgppa7L/HfwgwLgZ6NYs+Ag6uUmJRA== + brace-expansion@^1.1.7: version "1.1.11" resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" From 01bcb12fcfba7478112511610a37828db9e523bb Mon Sep 17 00:00:00 2001 From: Robert Rosman Date: Wed, 27 Mar 2024 21:46:30 +0100 Subject: [PATCH 08/10] feat: added notifications and failure alert (not fully tested yet) --- .../notifications/plugins/browser/__init__.py | 57 ++++++++++++++----- frontend/static/js/service-worker.js | 20 ++++--- 2 files changed, 56 insertions(+), 21 deletions(-) diff --git a/backend/notifications/plugins/browser/__init__.py b/backend/notifications/plugins/browser/__init__.py index 22c56db6a..0c873c625 100644 --- a/backend/notifications/plugins/browser/__init__.py +++ b/backend/notifications/plugins/browser/__init__.py @@ -37,24 +37,20 @@ def env_vars(self) -> Dict: }, } - def i(self, s: str) -> str: - return f"{s}" - - def b(self, s: str): - return f"{s}" - - def u(self, s: str): - return f"{s}" - def send_notification( self, config: Dict, title: str, message: str, - file_content: Optional[bytes] = None, - timeout: float = 5.0, + link: str, + tag: str, + image: str, ) -> None: vapid_subject = os.environ.get('VAPID_SUBJECT') + vapid_private_key = os.environ.get('VAPID_PRIVATE_KEY') + if not vapid_subject or not vapid_private_key or not config['subscriptions']: + LOGGER.warn("Missing configuration, won't send notifications to browser") + return for subscription in config['subscriptions']: try: @@ -66,8 +62,11 @@ def send_notification( data=json.dumps({ "title": title, "message": message, + "image": image, + "url": link, + "tag": tag, }), - vapid_private_key=os.environ.get('VAPID_PRIVATE_KEY'), + vapid_private_key=vapid_private_key, vapid_claims={ "sub": f'mailto:{vapid_subject}', } @@ -84,16 +83,46 @@ def send_notification( ) def send_failure_alert(self, context: FailureAlertContext) -> None: - LOGGER.warn("Not implemented yet") + link = site.build_full_url(f'/printers/{context.printer.id}/control') + title = self.get_failure_alert_title(context=context, link=link) + text = self.get_failure_alert_text(context=context, link=link) + if not title or not text: + return + + self.send_notification( + access_token=access_token, + title=title, + body=text, + link=link, + tag=context.printer.name, + image=context.img_url, + ) def send_printer_notification(self, context: PrinterNotificationContext) -> None: - LOGGER.warn("Not implemented yet") + title = self.get_printer_notification_title(context=context) + text = self.get_printer_notification_text(context=context) + if not text or not title: + return + + link = site.build_full_url(f'/printers/{context.printer.id}/control') + + self.send_notification( + access_token=access_token, + title=title, + body=text, + link=link, + tag=context.printer.name, + image=context.img_url, + ) def send_test_message(self, context: TestMessageContext) -> None: self.send_notification( config=context.config, title='Test Notification', message='It works!', + image="http://localhost:3334/media/tsd-pics/snapshots/1/1711225060.616871_rotated.jpg?digest=YidtXHg5MEJceDA3XHgxMlx4ZTl2XHgwNFx4OWV7XHg5Y3JjXHg5NGczP1x4ODVceGJhXHhhMFx4MTBfXHgxZVx4YWRceGY2XHhjNlx4ZTZceGI3XHg5ZDdsXHIn", + link="http://localhost:3334/printers/1/control", + tag="printer1" ) diff --git a/frontend/static/js/service-worker.js b/frontend/static/js/service-worker.js index 63fd736d4..4e9cad792 100644 --- a/frontend/static/js/service-worker.js +++ b/frontend/static/js/service-worker.js @@ -3,16 +3,22 @@ self.addEventListener("push", (event) => { return; } let data = event.data.json(); - const image = "https://www.obico.io/wwwimg/favicon.png"; + const icon = "https://obico.io/img/favicon.png"; const options = { body: data.message, - icon: image, + icon, + image: data.image, + tag: data.tag, + renotify: true, + requireInteraction: true, + data: { + url: data.url + } }; self.registration.showNotification(data.title, options); }); -// TODO -// self.addEventListener("notificationClick", (event) => { -// event.notification.close(); -// event.waitUntil(self.clients.openWindow("https://app.obico.io")); -// }); +self.addEventListener("notificationClick", (event) => { + event.notification.close(); + event.waitUntil(self.clients.openWindow(event.notification.data.url)); +}); From 76368f8e57432c39e03a4860d29b4a556a73922a Mon Sep 17 00:00:00 2001 From: Robert Rosman Date: Mon, 1 Apr 2024 20:40:47 +0200 Subject: [PATCH 09/10] feat: add real failure alert and notification --- .../notifications/plugins/browser/__init__.py | 27 ++++++++----------- 1 file changed, 11 insertions(+), 16 deletions(-) diff --git a/backend/notifications/plugins/browser/__init__.py b/backend/notifications/plugins/browser/__init__.py index 0c873c625..6590bcfe4 100644 --- a/backend/notifications/plugins/browser/__init__.py +++ b/backend/notifications/plugins/browser/__init__.py @@ -83,36 +83,31 @@ def send_notification( ) def send_failure_alert(self, context: FailureAlertContext) -> None: - link = site.build_full_url(f'/printers/{context.printer.id}/control') title = self.get_failure_alert_title(context=context, link=link) text = self.get_failure_alert_text(context=context, link=link) - if not title or not text: - return + link = site.build_full_url(f'/printers/{context.printer.id}/control') self.send_notification( - access_token=access_token, + config=context.config, title=title, - body=text, + message=message, + image=context.img_url, link=link, tag=context.printer.name, - image=context.img_url, ) def send_printer_notification(self, context: PrinterNotificationContext) -> None: title = self.get_printer_notification_title(context=context) - text = self.get_printer_notification_text(context=context) - if not text or not title: - return - + message = self.get_printer_notification_text(context=context) link = site.build_full_url(f'/printers/{context.printer.id}/control') self.send_notification( - access_token=access_token, + config=context.config, title=title, - body=text, + message=message, + image=context.img_url, link=link, tag=context.printer.name, - image=context.img_url, ) def send_test_message(self, context: TestMessageContext) -> None: @@ -120,9 +115,9 @@ def send_test_message(self, context: TestMessageContext) -> None: config=context.config, title='Test Notification', message='It works!', - image="http://localhost:3334/media/tsd-pics/snapshots/1/1711225060.616871_rotated.jpg?digest=YidtXHg5MEJceDA3XHgxMlx4ZTl2XHgwNFx4OWV7XHg5Y3JjXHg5NGczP1x4ODVceGJhXHhhMFx4MTBfXHgxZVx4YWRceGY2XHhjNlx4ZTZceGI3XHg5ZDdsXHIn", - link="http://localhost:3334/printers/1/control", - tag="printer1" + image="", + link="", + tag="test" ) From 704e447c35bbd2e592e9aa679fb77c75f7661776 Mon Sep 17 00:00:00 2001 From: Robert Rosman Date: Mon, 1 Apr 2024 21:17:01 +0200 Subject: [PATCH 10/10] fix: show alerts --- frontend/src/notifications/plugins/BrowserPlugin.vue | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/frontend/src/notifications/plugins/BrowserPlugin.vue b/frontend/src/notifications/plugins/BrowserPlugin.vue index 2dc06b8dd..15126cfbe 100644 --- a/frontend/src/notifications/plugins/BrowserPlugin.vue +++ b/frontend/src/notifications/plugins/BrowserPlugin.vue @@ -10,10 +10,10 @@ >