mirror of
https://github.com/dgtlmoon/changedetection.io.git
synced 2026-07-19 21:57:27 +00:00
151 lines
5.3 KiB
Python
151 lines
5.3 KiB
Python
from flask_restful import Resource, abort
|
|
from flask import request
|
|
from . import auth, validate_openapi_request
|
|
|
|
_API_PROFILE_NAME = "API Default"
|
|
|
|
def _get_api_profile(datastore):
|
|
"""Return (uuid, profile_dict) for the API-managed system profile, or (None, None)."""
|
|
profiles = datastore.data['settings']['application'].get('notification_profile_data', {})
|
|
for uid, p in profiles.items():
|
|
if p.get('name') == _API_PROFILE_NAME:
|
|
return uid, p
|
|
return None, None
|
|
|
|
|
|
def _ensure_api_profile(datastore, urls):
|
|
"""Create or update the API Default profile and ensure it's linked to system."""
|
|
import uuid as uuid_mod
|
|
|
|
app = datastore.data['settings']['application']
|
|
app.setdefault('notification_profile_data', {})
|
|
app.setdefault('notification_profiles', [])
|
|
|
|
uid, profile = _get_api_profile(datastore)
|
|
if uid is None:
|
|
uid = str(uuid_mod.uuid4())
|
|
profile = {'uuid': uid, 'name': _API_PROFILE_NAME, 'type': 'apprise', 'config': {}}
|
|
app['notification_profile_data'][uid] = profile
|
|
|
|
profile['config']['notification_urls'] = urls
|
|
|
|
if uid not in app['notification_profiles']:
|
|
app['notification_profiles'].append(uid)
|
|
|
|
datastore.needs_write = True
|
|
return uid, profile
|
|
|
|
|
|
class Notifications(Resource):
|
|
def __init__(self, **kwargs):
|
|
self.datastore = kwargs['datastore']
|
|
|
|
@auth.check_token
|
|
@validate_openapi_request('getNotifications')
|
|
def get(self):
|
|
"""Return Notification URL List (from the API Default profile)."""
|
|
_, profile = _get_api_profile(self.datastore)
|
|
urls = profile['config'].get('notification_urls', []) if profile else []
|
|
return {'notification_urls': urls}, 200
|
|
|
|
@auth.check_token
|
|
@validate_openapi_request('addNotifications')
|
|
def post(self):
|
|
"""Add Notification URLs to the API Default profile."""
|
|
json_data = request.get_json()
|
|
notification_urls = json_data.get("notification_urls", [])
|
|
|
|
from wtforms import ValidationError
|
|
try:
|
|
validate_notification_urls(notification_urls)
|
|
except ValidationError as e:
|
|
return str(e), 400
|
|
|
|
_, profile = _get_api_profile(self.datastore)
|
|
existing = list(profile['config'].get('notification_urls', []) if profile else [])
|
|
|
|
added = []
|
|
for url in notification_urls:
|
|
clean = url.strip()
|
|
if clean and clean not in existing:
|
|
existing.append(clean)
|
|
added.append(clean)
|
|
|
|
if not added:
|
|
return "No valid notification URLs were added", 400
|
|
|
|
_ensure_api_profile(self.datastore, existing)
|
|
self.datastore.commit()
|
|
return {'notification_urls': existing}, 201
|
|
|
|
@auth.check_token
|
|
@validate_openapi_request('replaceNotifications')
|
|
def put(self):
|
|
"""Replace Notification URLs in the API Default profile."""
|
|
json_data = request.get_json()
|
|
notification_urls = json_data.get("notification_urls", [])
|
|
|
|
from wtforms import ValidationError
|
|
try:
|
|
validate_notification_urls(notification_urls)
|
|
except ValidationError as e:
|
|
return str(e), 400
|
|
|
|
if not isinstance(notification_urls, list):
|
|
return "Invalid input format", 400
|
|
|
|
clean_urls = [url.strip() for url in notification_urls if isinstance(url, str)]
|
|
|
|
if clean_urls:
|
|
_ensure_api_profile(self.datastore, clean_urls)
|
|
else:
|
|
# Empty list: remove the profile entirely
|
|
uid, _ = _get_api_profile(self.datastore)
|
|
if uid:
|
|
app = self.datastore.data['settings']['application']
|
|
app['notification_profile_data'].pop(uid, None)
|
|
if uid in app.get('notification_profiles', []):
|
|
app['notification_profiles'].remove(uid)
|
|
self.datastore.needs_write = True
|
|
|
|
self.datastore.commit()
|
|
return {'notification_urls': clean_urls}, 200
|
|
|
|
@auth.check_token
|
|
@validate_openapi_request('deleteNotifications')
|
|
def delete(self):
|
|
"""Delete specific Notification URLs from the API Default profile."""
|
|
json_data = request.get_json()
|
|
urls_to_delete = json_data.get("notification_urls", [])
|
|
if not isinstance(urls_to_delete, list):
|
|
abort(400, message="Expected a list of notification URLs.")
|
|
|
|
uid, profile = _get_api_profile(self.datastore)
|
|
if not profile:
|
|
abort(400, message="No matching notification URLs found.")
|
|
|
|
current = list(profile['config'].get('notification_urls', []))
|
|
deleted = []
|
|
for url in urls_to_delete:
|
|
clean = url.strip()
|
|
if clean in current:
|
|
current.remove(clean)
|
|
deleted.append(clean)
|
|
|
|
if not deleted:
|
|
abort(400, message="No matching notification URLs found.")
|
|
|
|
profile['config']['notification_urls'] = current
|
|
self.datastore.needs_write = True
|
|
self.datastore.commit()
|
|
return 'OK', 204
|
|
|
|
|
|
def validate_notification_urls(notification_urls):
|
|
from changedetectionio.forms import ValidateAppRiseServers
|
|
validator = ValidateAppRiseServers()
|
|
class DummyForm: pass
|
|
dummy_form = DummyForm()
|
|
field = type("Field", (object,), {"data": notification_urls, "gettext": lambda self, x: x})()
|
|
validator(dummy_form, field)
|