diff --git a/server/CHANGELOG.md b/server/CHANGELOG.md index eb34240..d092b29 100644 --- a/server/CHANGELOG.md +++ b/server/CHANGELOG.md @@ -1,5 +1,9 @@ # Changelog +## [2.5.0] - 2026-05-14 +### Added +- Added Nextcloud Talk support via OCS Chat API + ## [2.4.0] - 2026-05-13 ### Added - Added support for GoAlert Rotation shift changes diff --git a/server/src/config.yml b/server/src/config.yml index 3970932..7952aa2 100644 --- a/server/src/config.yml +++ b/server/src/config.yml @@ -1,4 +1,8 @@ --- matrix_homeserver: "" -matrix_access_token": "" -matrix_user_id: "" \ No newline at end of file +matrix_access_token: "" +matrix_user_id: "" + +nextcloud_server: "" +nextcloud_username: "" +nextcloud_password: "" \ No newline at end of file diff --git a/server/src/hooks.yml b/server/src/hooks.yml index 8bf2141..cef9b23 100644 --- a/server/src/hooks.yml +++ b/server/src/hooks.yml @@ -2,3 +2,8 @@ 2345555XE: transport: "simplex" target: "#Bottest" + +# Nextcloud Talk example: +# myhook: +# transport: "nextcloud" +# target: "conversation_token_here" diff --git a/server/src/tellmesrv.py b/server/src/tellmesrv.py index 72687a7..696a589 100644 --- a/server/src/tellmesrv.py +++ b/server/src/tellmesrv.py @@ -10,8 +10,12 @@ from pprint import pprint from nio import AsyncClient, MatrixRoom, RoomMessageText from nio.exceptions import OlmUnverifiedDeviceError import asyncio +import urllib.request +import urllib.parse +import urllib.error +import base64 -__version__ = "2.4.0" +__version__ = "2.5.0" versionstring='Taurix TellMe server v' + __version__ log_dir = '/var/log/tellme' @@ -198,6 +202,38 @@ def send_matrix_message(target, message): return False +def send_nextcloud_message(target, message): + try: + server = config.get('nextcloud_server') + username = config.get('nextcloud_username') + password = config.get('nextcloud_password') + + if not server or not username or not password: + log.error("Nextcloud Talk credentials not configured") + return False + + url = f"{server.rstrip('/')}/ocs/v2.php/apps/spreed/api/v1/chat/{target}" + + credentials = base64.b64encode(f"{username}:{password}".encode()).decode() + + data = urllib.parse.urlencode({'message': message}).encode() + + req = urllib.request.Request(url, data=data) + req.add_header('OCS-APIRequest', 'true') + req.add_header('Content-Type', 'application/x-www-form-urlencoded') + req.add_header('Authorization', f'Basic {credentials}') + + response = urllib.request.urlopen(req) + log.info("Nextcloud Talk message sent to conversation %s, response: %d" % (target, response.status)) + return True + except urllib.error.HTTPError as e: + log.error("Nextcloud Talk HTTP error: %d %s" % (e.code, e.reason)) + return False + except Exception as e: + log.error("Failed to send Nextcloud Talk message: %s" % (e)) + return False + + def get_hook(hook_id): global hooks hook = hooks.get(str(hook_id)) @@ -274,6 +310,18 @@ def webhook_receiver(id): else: log.error("No target found, dropping message") return jsonify({'message': 'No target found, dropping message'}), 400 + elif transport == 'nextcloud': + if target is not None: + log.info(target) + if message is not None: + if not send_nextcloud_message(target, message): + return jsonify({'message': 'Failed to send Nextcloud Talk message'}), 500 + else: + log.error("No message, dropping") + return jsonify({'message': 'No message, dropping'}), 400 + else: + log.error("No target found, dropping message") + return jsonify({'message': 'No target found, dropping message'}), 400 else: log.error("Unknown transport: %s" % (transport)) return jsonify({'message': 'Unknown transport'}), 400