diff --git a/changedetectionio/blueprint/browser_notifications/__init__.py b/changedetectionio/blueprint/browser_notifications/__init__.py new file mode 100644 index 000000000..29606b619 --- /dev/null +++ b/changedetectionio/blueprint/browser_notifications/__init__.py @@ -0,0 +1 @@ +# Browser notifications blueprint \ No newline at end of file diff --git a/changedetectionio/blueprint/browser_notifications/browser_notifications.py b/changedetectionio/blueprint/browser_notifications/browser_notifications.py new file mode 100644 index 000000000..2f30abe0b --- /dev/null +++ b/changedetectionio/blueprint/browser_notifications/browser_notifications.py @@ -0,0 +1,76 @@ +from flask import Blueprint, jsonify, request +from loguru import logger + + +def construct_blueprint(datastore): + browser_notifications_blueprint = Blueprint('browser_notifications', __name__) + + @browser_notifications_blueprint.route("/test", methods=['POST']) + def test_browser_notification(): + """Send a test browser notification using the apprise handler""" + try: + from changedetectionio.notification.apprise_plugin.custom_handlers import apprise_browser_notification_handler + + # Check if there are any subscriptions + browser_subscriptions = datastore.data.get('settings', {}).get('application', {}).get('browser_subscriptions', []) + if not browser_subscriptions: + return jsonify({'success': False, 'message': 'No browser subscriptions found'}), 404 + + # Get notification data from request or use defaults + data = request.get_json() or {} + title = data.get('title', 'Test Notification') + body = data.get('body', 'This is a test notification from changedetection.io') + + # Use the apprise handler directly + success = apprise_browser_notification_handler( + body=body, + title=title, + notify_type='info', + meta={'url': 'browser://test'} + ) + + if success: + subscription_count = len(browser_subscriptions) + return jsonify({ + 'success': True, + 'message': f'Test notification sent successfully to {subscription_count} subscriber(s)' + }) + else: + return jsonify({'success': False, 'message': 'Failed to send test notification'}), 500 + + except ImportError: + logger.error("Browser notification handler not available") + return jsonify({'success': False, 'message': 'Browser notification handler not available'}), 500 + except Exception as e: + logger.error(f"Failed to send test browser notification: {e}") + return jsonify({'success': False, 'message': f'Error: {str(e)}'}), 500 + + @browser_notifications_blueprint.route("/clear", methods=['POST']) + def clear_all_browser_notifications(): + """Clear all browser notification subscriptions from the datastore""" + try: + # Get current subscription count + browser_subscriptions = datastore.data.get('settings', {}).get('application', {}).get('browser_subscriptions', []) + subscription_count = len(browser_subscriptions) + + # Clear all subscriptions + if 'settings' not in datastore.data: + datastore.data['settings'] = {} + if 'application' not in datastore.data['settings']: + datastore.data['settings']['application'] = {} + + datastore.data['settings']['application']['browser_subscriptions'] = [] + datastore.needs_write = True + + logger.info(f"Cleared {subscription_count} browser notification subscriptions") + + return jsonify({ + 'success': True, + 'message': f'Cleared {subscription_count} browser notification subscription(s)' + }) + + except Exception as e: + logger.error(f"Failed to clear all browser notifications: {e}") + return jsonify({'success': False, 'message': f'Clear all failed: {str(e)}'}), 500 + + return browser_notifications_blueprint \ No newline at end of file diff --git a/changedetectionio/flask_app.py b/changedetectionio/flask_app.py index b6dc57e3f..921b597e1 100644 --- a/changedetectionio/flask_app.py +++ b/changedetectionio/flask_app.py @@ -516,71 +516,13 @@ def changedetection_app(config=None, datastore_o=None): except FileNotFoundError: abort(404) - @app.route("/test-browser-notification", methods=['POST']) - def test_browser_notification(): - """Send a test browser notification using the apprise handler""" - try: - from flask import jsonify - from changedetectionio.notification.apprise_plugin.custom_handlers import apprise_browser_notification_handler - - # Check if there are any subscriptions - browser_subscriptions = datastore.data.get('settings', {}).get('application', {}).get('browser_subscriptions', []) - if not browser_subscriptions: - return jsonify({'success': False, 'message': 'No browser subscriptions found'}), 404 - - # Send test notification using apprise handler - success = apprise_browser_notification_handler( - body='This is a test browser notification from changedetection.io', - title='Test Browser Notification', - notify_type='info', - meta={'url': 'browser://test'} - ) - - if success: - return jsonify({ - 'success': True, - 'message': f'Test notification sent to {len(browser_subscriptions)} subscriber(s)' - }) - else: - return jsonify({'success': False, 'message': 'Failed to send test notification'}), 500 - - except Exception as e: - logger.error(f"Test browser notification failed: {e}") - return jsonify({'success': False, 'message': f'Error: {str(e)}'}), 500 - - @app.route("/clear-all-browser-notifications", methods=['POST']) - def clear_all_browser_notifications(): - """Clear all browser notification subscriptions from the datastore""" - try: - from flask import jsonify - - # Get current subscription count - browser_subscriptions = datastore.data.get('settings', {}).get('application', {}).get('browser_subscriptions', []) - subscription_count = len(browser_subscriptions) - - # Clear all subscriptions - if 'settings' not in datastore.data: - datastore.data['settings'] = {} - if 'application' not in datastore.data['settings']: - datastore.data['settings']['application'] = {} - - datastore.data['settings']['application']['browser_subscriptions'] = [] - datastore.needs_write = True - - logger.info(f"Cleared {subscription_count} browser notification subscriptions") - - return jsonify({ - 'success': True, - 'message': f'Cleared {subscription_count} browser notification subscription(s)' - }) - - except Exception as e: - logger.error(f"Failed to clear all browser notifications: {e}") - return jsonify({'success': False, 'message': f'Clear all failed: {str(e)}'}), 500 import changedetectionio.blueprint.browser_steps as browser_steps app.register_blueprint(browser_steps.construct_blueprint(datastore), url_prefix='/browser-steps') + import changedetectionio.blueprint.browser_notifications.browser_notifications as browser_notifications + app.register_blueprint(browser_notifications.construct_blueprint(datastore), url_prefix='/browser-notifications') + from changedetectionio.blueprint.imports import construct_blueprint as construct_import_blueprint app.register_blueprint(construct_import_blueprint(datastore, update_q, queuedWatchMetaData), url_prefix='/imports') diff --git a/changedetectionio/notification/BrowserNotifications.py b/changedetectionio/notification/BrowserNotifications.py index fb128fb1b..a71882af4 100644 --- a/changedetectionio/notification/BrowserNotifications.py +++ b/changedetectionio/notification/BrowserNotifications.py @@ -152,38 +152,6 @@ class BrowserNotificationsUnsubscribe(Resource): return {'success': False, 'message': f'Unsubscribe failed: {str(e)}'}, 500 -class BrowserNotificationsClearAll(Resource): - """Clear all browser notification subscriptions""" - - @marshal_with(browser_notifications_fields) - def post(self): - try: - # Get datastore - datastore = current_app.config.get('DATASTORE') - if not datastore: - return {'success': False, 'message': 'Datastore not available'}, 500 - - # Get current subscription count - browser_subscriptions = datastore.data.get('settings', {}).get('application', {}).get('browser_subscriptions', []) - subscription_count = len(browser_subscriptions) - - # Clear all subscriptions - if 'settings' not in datastore.data: - datastore.data['settings'] = {} - if 'application' not in datastore.data['settings']: - datastore.data['settings']['application'] = {} - - datastore.data['settings']['application']['browser_subscriptions'] = [] - datastore.needs_write = True - - logger.info(f"Cleared {subscription_count} browser notification subscriptions") - - return {'success': True, 'message': f'Cleared {subscription_count} browser notification subscription(s)'} - - except Exception as e: - logger.error(f"Failed to clear all browser notifications: {e}") - return {'success': False, 'message': f'Clear all failed: {str(e)}'}, 500 - class BrowserNotificationsTest(Resource): """Send a test browser notification""" diff --git a/changedetectionio/static/js/browser-notifications.js b/changedetectionio/static/js/browser-notifications.js index 09a0dd862..2f01a2bcb 100644 --- a/changedetectionio/static/js/browser-notifications.js +++ b/changedetectionio/static/js/browser-notifications.js @@ -274,7 +274,7 @@ class BrowserNotifications { } } - const response = await fetch('/test-browser-notification', { + const response = await fetch('/browser-notifications/test', { method: 'POST', headers: { 'Content-Type': 'application/json', @@ -403,7 +403,7 @@ Would you like to automatically clear the old subscription and retry?`; */ try { // Call the server to clear ALL subscriptions from datastore - const response = await fetch('/clear-all-browser-notifications', { + const response = await fetch('/browser-notifications/clear', { method: 'POST', headers: { 'Content-Type': 'application/json',