From c0561634f59c8f1ad776aba77d0c688d5f8856c6 Mon Sep 17 00:00:00 2001 From: Yannik Schmidt Date: Fri, 16 Feb 2024 14:49:10 +0100 Subject: [PATCH 1/9] add: debug & smtp --- client/dispatch-query.py | 23 ++++++++++++++++++++--- client/smtp.py | 37 +++++++++++++++++++++++++++++++++++++ 2 files changed, 57 insertions(+), 3 deletions(-) create mode 100644 client/smtp.py diff --git a/client/dispatch-query.py b/client/dispatch-query.py index 4e0236d..91acb90 100755 --- a/client/dispatch-query.py +++ b/client/dispatch-query.py @@ -5,13 +5,26 @@ import subprocess import os import requests from functools import wraps +import smtphelper HTTP_NOT_FOUND = 404 AUTH = None -def email_address(dispatch_uuid, user_topic, message, smtp_target, smtp_user, smtp_pass): - '''Send message via email''' +def debug_send(uuid, data, fail_it=False): + '''Dummy function to print and ack a dispatch for debugging''' + print(json.dumps(data, intent=2)) + if fail_it: + report_failed_dispatch(uuid, "Dummy Error for Debugging") + else: + confirm_dispatch(uuid) + + +def email_send(dispatch_uuid, email_address, message, smtp_target, smtp_user, smtp_pass): + '''Send message via email''' + + subject = "Atlantis Dispatch" + smtphelper.smtp_send(smtp_target, smtp_user, smtp_pass, email_address, subject, message) report_failed_dispatch(uuid, "Email dispatch not yet implemented") def ntfy_send(dispatch_uuid, user_topic, message, ntfy_push_target, ntfy_user, ntfy_pass): @@ -117,7 +130,11 @@ if __name__ == "__main__": elif method == "ntfy": ntfy_send(dispatch_uuid, user_topic, message, ntfy_push_target, ntfy_user, ntfy_pass) elif method == "email": - email_send(email_address, message) + email_send(dispatch_uuid, email_address, message, smtp_target, smtp_user, smtp_pass) + elif method == "debug": + debug_send(uuid, entry) + elif method == "debug-fail": + debug_send(uuid, entry, fail_it=True) else: print("Unsupported dispatch method {}".format(entry["method"]), sys=sys.stderr) continue diff --git a/client/smtp.py b/client/smtp.py new file mode 100644 index 0000000..3355328 --- /dev/null +++ b/client/smtp.py @@ -0,0 +1,37 @@ +import smtplib +from email.mime.text import MIMEText +from email.mime.multipart import MIMEMultipart + +def smtp_send(server, user, password, recipient, subject, body): + + # Email and password for authentication + sender_email = f'{user}@{server}' + sender_password = password + + # Recipient email address + recipient_email = recipient + + # SMTP server details + smtp_server = server + smtp_port = 587 # Default port for TLS connection + + # Create a message + message = MIMEMultipart() + message['From'] = sender_email + message['To'] = recipient_email + message['Subject'] = subject + + # Add body to email + body = body + message.attach(MIMEText(body, 'plain')) + + # Establish a connection to the SMTP server + server = smtplib.SMTP(smtp_server, smtp_port) + server.starttls() # Secure the connection + server.login(sender_email, sender_password) + + # Send the email + server.sendmail(sender_email, recipient_email, message.as_string()) + + # Close the connection + server.quit() From 9816036d90849d3420c5e0dd6241481e95ea6896 Mon Sep 17 00:00:00 2001 From: Yannik Schmidt Date: Fri, 16 Feb 2024 18:54:42 +0100 Subject: [PATCH 2/9] wip: ntfy & smtp --- client/dispatch-query.py | 55 +++++++++++++++++++++---------- client/{smtp.py => smtphelper.py} | 0 2 files changed, 38 insertions(+), 17 deletions(-) rename client/{smtp.py => smtphelper.py} (100%) diff --git a/client/dispatch-query.py b/client/dispatch-query.py index 91acb90..88ec485 100755 --- a/client/dispatch-query.py +++ b/client/dispatch-query.py @@ -1,19 +1,22 @@ #!/usr/bin/python3 import sys +import argparse import subprocess import os import requests -from functools import wraps import smtphelper +import json HTTP_NOT_FOUND = 404 + +DISPATCH_SERVER = None AUTH = None def debug_send(uuid, data, fail_it=False): '''Dummy function to print and ack a dispatch for debugging''' - print(json.dumps(data, intent=2)) + print(json.dumps(data, indent=2)) if fail_it: report_failed_dispatch(uuid, "Dummy Error for Debugging") else: @@ -31,19 +34,37 @@ def ntfy_send(dispatch_uuid, user_topic, message, ntfy_push_target, ntfy_user, n '''Send message via NTFY topic''' try: - r = requests.post(ntfy_push_target, auth=(ntfy_user, ntfy_pass) , json=payload) + + # build message # + payload = { + "topic" : user_topic or "test", #TODO fix topic + "message" : message, + "title" : "Atlantis Notify", + #"tags" : [], + #"priority" : 4, + #"attach" : None, + #"click" : None, + #"actions" : [] + } + + # send # + r = requests.post(ntfy_push_target, auth=(ntfy_user, ntfy_pass), json=payload) + print(r.status_code, r.text, payload) r.raise_for_status() - confirm_dispatch(uuid) + + # talk to dispatch # + confirm_dispatch(dispatch_uuid) + except requests.exceptions.HTTPError as e: - report_failed_dispatch(uuid, str(e)) + report_failed_dispatch(dispatch_uuid, str(e)) except requests.exceptions.ConnectionError as e: - report_failed_dispatch(uuid, str(e)) + report_failed_dispatch(dispatch_uuid, str(e)) def report_failed_dispatch(uuid, error): '''Inform the server that the dispatch has failed''' - response = requests.post(args.dispatch_target + "/report-dispatch-failed", - json={ "uuid" : uuid, "error" : error }) + payload = [{ "uuid" : uuid, "error" : error }] + response = requests.post(DISPATCH_SERVER + "/report-dispatch-failed", json=payload, auth=AUTH) if response.status_code not in [200, 204]: print("Failed to report back failed dispatch for {} ({})".format( @@ -52,8 +73,8 @@ def report_failed_dispatch(uuid, error): def confirm_dispatch(uuid): '''Confirm to server that message has been dispatched and can be removed''' - response = requests.post(target + "/confirm-dispatch", json=[{ "uuid" : uuid }], - auth=(args.user, args.password)) + payload = [{ "uuid" : uuid }] + response = requests.post(DISPATCH_SERVER + "/confirm-dispatch", json=payload, auth=AUTH) if response.status_code not in [200, 204]: print("Failed to confirm dispatch with server for {} ({})".format( @@ -79,7 +100,8 @@ if __name__ == "__main__": args = parser.parse_args() - # set authentication # + # set dispatch server & authentication # + DISPATCH_SERVER = args.dispatch_server AUTH = (args.dispatch_user, args.dispatch_password) dispatch_server = args.dispatch_server or os.environ.get("DISPATCH_SERVER") @@ -95,8 +117,7 @@ if __name__ == "__main__": smtp_pass = args.smtp_pass or os.environ.get("SMTP_PASS") # request dispatches # - response = requests.get(args.target + "/get-dispatch".format(args.method), - auth=(args.user, args.password)) + response = requests.get(args.dispatch_server + "/get-dispatch?method=all", auth=AUTH) # check status # if response.status_code == HTTP_NOT_FOUND: @@ -114,8 +135,8 @@ if __name__ == "__main__": # iterate over dispatch requests # for entry in response.json(): - user = entry["person"] - dispatch_uuid = entry["uid"] + user = entry["username"] + dispatch_uuid = entry["uuid"] method = entry["method"] message = entry["message"] @@ -132,9 +153,9 @@ if __name__ == "__main__": elif method == "email": email_send(dispatch_uuid, email_address, message, smtp_target, smtp_user, smtp_pass) elif method == "debug": - debug_send(uuid, entry) + debug_send(dispatch_uuid, entry) elif method == "debug-fail": - debug_send(uuid, entry, fail_it=True) + debug_send(dispatch_uuid, entry, fail_it=True) else: print("Unsupported dispatch method {}".format(entry["method"]), sys=sys.stderr) continue diff --git a/client/smtp.py b/client/smtphelper.py similarity index 100% rename from client/smtp.py rename to client/smtphelper.py From 46260edfaaf226e79994b63da864c4eec9095551 Mon Sep 17 00:00:00 2001 From: Yannik Schmidt Date: Fri, 16 Feb 2024 18:55:15 +0100 Subject: [PATCH 3/9] refactor: better method switching & ntfy support --- server/interface.py | 125 +++++++++++++++++++++++++++++++++----------- 1 file changed, 95 insertions(+), 30 deletions(-) diff --git a/server/interface.py b/server/interface.py index 31c2854..44b6525 100755 --- a/server/interface.py +++ b/server/interface.py @@ -33,11 +33,35 @@ class DispatchObject(db.Model): timestamp = Column(Integer, primary_key=True) phone = Column(String) email = Column(String) + + title = Column(String) message = Column(String, primary_key=True) method = Column(String) + dispatch_secret = Column(String) dispatch_error = Column(String) + def serialize(self): + ret = { + "person" : self.username, # legacy field TODO remove at some point + "username" : self.username, + "timestamp" : self.timestamp, + "phone" : self.phone, + "email" : self.email, + "title" : self.title, + "message" : self.message, + "uuid" : self.dispatch_secret, + "method" : self.method, + "error" : self.dispatch_error, + } + + # fix bytes => string from LDAP # + for key, value in ret.items(): + if type(value) == bytes: + ret[key] = value.decode("utf-8") + + return ret + @app.route('/get-dispatch-status') def get_dispatch_status(): '''Retrive the status of a specific dispatch by it's secret''' @@ -56,6 +80,7 @@ def get_dispatch(): method = flask.request.args.get("method") timeout = flask.request.args.get("timeout") or 5 # timeout in seconds + timeout = int(timeout) if not method: return (500, "Missing Dispatch Target (signal|email|phone|ntfy|all)") @@ -72,34 +97,61 @@ def get_dispatch(): else: dispatch_objects = lines_timeout.all() - # accumulate messages by person # - dispatch_by_person = dict() - dispatch_secrets = [] - for dobj in dispatch_objects: - if dobj.username not in dispatch_by_person: - dispatch_by_person.update({ dobj.username : dobj.message }) - dispatch_secrets.append(dobj.dispatch_secret) - else: - dispatch_by_person[dobj.username] += "\n{}".format(dobj.message) - dispatch_secrets.append(dobj.dispatch_secret) + # TODO THIS IS THE NEW MASTER PART + if method and method != "signal": + print([ d.serialize() for d in dispatch_objects]) + return flask.jsonify([ d.serialize() for d in dispatch_objects]) + else: + # TODO THIS PART WILL BE REMOVED ## + # accumulate messages by person # + dispatch_by_person = dict() + dispatch_secrets = [] + for dobj in dispatch_objects: + if dobj.username not in dispatch_by_person: + dispatch_by_person.update({ dobj.username : dobj.message }) + dispatch_secrets.append(dobj.dispatch_secret) + else: + dispatch_by_person[dobj.username] += "\n{}".format(dobj.message) + dispatch_secrets.append(dobj.dispatch_secret) - response = [ { "person" : tupel[0].decode("utf-8"), - "message" : tupel[1], - "method" : method, - "uids" : dispatch_secrets - } for tupel in dispatch_by_person.items() ] + response = [ { "person" : tupel[0].decode("utf-8"), + "message" : tupel[1], + "method" : method, + "uids" : dispatch_secrets + } for tupel in dispatch_by_person.items() ] - # add phone numbers and emails # - for obj in response: - for person in dispatch_objects: - if obj["person"] == person.username.decode("utf-8"): - if person.email: - obj.update({ "email" : person.email.decode("utf-8") }) - if person.phone: - obj.update({ "phone" : person.phone.decode("utf-8") }) + # add phone numbers and emails # + for obj in response: + for person in dispatch_objects: + if obj["person"] == person.username.decode("utf-8"): + if person.email: + obj.update({ "email" : person.email.decode("utf-8") }) + if person.phone: + obj.update({ "phone" : person.phone.decode("utf-8") }) - return flask.jsonify(response) + return flask.jsonify(response) +@app.route('/report-dispatch-failed', methods=["POST"]) +def reject_dispatch(): + '''Inform the server that a dispatch has failed''' + + rejects = flask.request.json + + for r in rejects: + + uuid = r["uuid"] + error = r["error"] + dpo = db.session.query(DispatchObject).filter( + DispatchObject.dispatch_secret == uuid).first() + + if not dpo: + return ("No pending dispatch for this UID/Secret", 404) + + dpo.dispatch_error = error + db.session.merge(dpo) + db.session.commit() + + return ("", 204) @app.route('/confirm-dispatch', methods=["POST"]) def confirm_dispatch(): @@ -109,8 +161,9 @@ def confirm_dispatch(): for c in confirms: - uid = c["uid"] - dpo = db.session.query(DispatchObject).filter(DispatchObject.dispatch_secret == uid).first() + uuid = c["uuid"] + dpo = db.session.query(DispatchObject).filter( + DispatchObject.dispatch_secret == uuid).first() if not dpo: return ("No pending dispatch for this UID/Secret", 404) @@ -139,6 +192,11 @@ def smart_send_to_clients(): users = instructions.get("users") groups = instructions.get("groups") message = instructions.get("msg") + method = instructions.get("method") + + # allow single use string instead of array # + if type(users) == str: + users = [users] struct = instructions.get("data") if struct: @@ -148,13 +206,17 @@ def smart_send_to_clients(): print(str(e), file=sys.stderr) return (e.response(), 408) + if method in ["debug", "debug-fail"]: + persons = [ldaptools.Person(cn="none", username=users[0], name="Mr. Debug", + email="invalid@nope.notld", phone="0")] + else: + persons = ldaptools.select_targets(users, groups, app.config["LDAP_ARGS"]) - persons = ldaptools.select_targets(users, groups, app.config["LDAP_ARGS"]) - dispatch_secrets = save_in_dispatch_queue(persons, message) + dispatch_secrets = save_in_dispatch_queue(persons, message, method) return flask.jsonify(dispatch_secrets) -def save_in_dispatch_queue(persons, message): +def save_in_dispatch_queue(persons, message, method): dispatch_secrets = [] @@ -166,10 +228,13 @@ def save_in_dispatch_queue(persons, message): # this secret will be needed to confirm the message as dispatched # dispatch_secret = secrets.token_urlsafe(32) + # TODO fix this + master_method = "signal" + obj = DispatchObject(username=p.username, phone=p.phone, email=p.email, - method="signal", + method=method or master_method, timestamp=datetime.datetime.now().timestamp(), dispatch_secret=dispatch_secret, message=message) From 7f468ba860c0bf9fcdae95443f20d61653923ad1 Mon Sep 17 00:00:00 2001 From: Yannik Schmidt Date: Fri, 16 Feb 2024 19:15:04 +0100 Subject: [PATCH 4/9] feat: add topic query from api --- client/dispatch-query.py | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/client/dispatch-query.py b/client/dispatch-query.py index 88ec485..8c93d66 100755 --- a/client/dispatch-query.py +++ b/client/dispatch-query.py @@ -30,9 +30,29 @@ def email_send(dispatch_uuid, email_address, message, smtp_target, smtp_user, sm smtphelper.smtp_send(smtp_target, smtp_user, smtp_pass, email_address, subject, message) report_failed_dispatch(uuid, "Email dispatch not yet implemented") +def ntfy_api_get_topic(ntfy_api_server, ntfy_api_token, username): + '''Get the topic of the user''' + + params = { + "user" : username, + "token" : ntfy_api_token, + } + + r = requests.get(ntfy_api_server + "/topic", params=params) + if r.status_code != 200: + print(r.text) + return None + else: + print(r.text) + return r.json().get("topic") + def ntfy_send(dispatch_uuid, user_topic, message, ntfy_push_target, ntfy_user, ntfy_pass): '''Send message via NTFY topic''' + if not user_topic: + report_failed_dispatch(dispatch_uuid, "No user topic") + return + try: # build message # @@ -90,6 +110,9 @@ if __name__ == "__main__": parser.add_argument('--dispatch-user') parser.add_argument('--dispatch-password') + parser.add_argument('--ntfy-api-server') + parser.add_argument('--ntfy-api-token') + parser.add_argument('--ntfy-push-target') parser.add_argument('--ntfy-user') parser.add_argument('--ntfy-pass') @@ -108,6 +131,9 @@ if __name__ == "__main__": dispatch_user = args.dispatch_user or os.environ.get("DISPATCH_USER") dispatch_password = args.dispatch_password or os.environ.get("DISPATCH_PASSWORD") + ntfy_api_server = args.ntfy_api_server or os.environ.get("NTFY_API_SERVER") + ntfy_api_token = args.ntfy_api_token or os.environ.get("NTFY_API_TOKEN") + ntfy_push_target = args.ntfy_push_target or os.environ.get("NTFY_PUSH_TARGET") ntfy_user = args.ntfy_user or os.environ.get("NTFY_USER") ntfy_pass = args.ntfy_pass or os.environ.get("NTFY_PASS") @@ -141,7 +167,6 @@ if __name__ == "__main__": message = entry["message"] # method dependent fields # - user_topic = entry.get("topic") phone = entry.get("phone") email_address = entry.get("email") @@ -149,6 +174,7 @@ if __name__ == "__main__": if method == "signal": pass elif method == "ntfy": + user_topic = ntfy_api_get_topic(ntfy_api_server, ntfy_api_token, user) ntfy_send(dispatch_uuid, user_topic, message, ntfy_push_target, ntfy_user, ntfy_pass) elif method == "email": email_send(dispatch_uuid, email_address, message, smtp_target, smtp_user, smtp_pass) From 7d3c449c16ba89858b157ce887527ce1de21aae8 Mon Sep 17 00:00:00 2001 From: Yannik Schmidt Date: Fri, 16 Feb 2024 19:47:22 +0100 Subject: [PATCH 5/9] fix: message title --- client/dispatch-query.py | 16 +++++++++------- server/interface.py | 6 ++++-- 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/client/dispatch-query.py b/client/dispatch-query.py index 8c93d66..b192ab5 100755 --- a/client/dispatch-query.py +++ b/client/dispatch-query.py @@ -46,7 +46,7 @@ def ntfy_api_get_topic(ntfy_api_server, ntfy_api_token, username): print(r.text) return r.json().get("topic") -def ntfy_send(dispatch_uuid, user_topic, message, ntfy_push_target, ntfy_user, ntfy_pass): +def ntfy_send(dispatch_uuid, user_topic, title, message, ntfy_push_target, ntfy_user, ntfy_pass): '''Send message via NTFY topic''' if not user_topic: @@ -57,13 +57,13 @@ def ntfy_send(dispatch_uuid, user_topic, message, ntfy_push_target, ntfy_user, n # build message # payload = { - "topic" : user_topic or "test", #TODO fix topic + "topic" : user_topic, "message" : message, - "title" : "Atlantis Notify", + "title" : title or "Atlantis Notify", #"tags" : [], - #"priority" : 4, + "priority" : 4, #"attach" : None, - #"click" : None, + "click" : "https://vid.pr0gramm.com/2022/11/06/ed66c8c5a9cd1a3b.mp4", #"actions" : [] } @@ -143,7 +143,7 @@ if __name__ == "__main__": smtp_pass = args.smtp_pass or os.environ.get("SMTP_PASS") # request dispatches # - response = requests.get(args.dispatch_server + "/get-dispatch?method=all", auth=AUTH) + response = requests.get(args.dispatch_server + "/get-dispatch?method=all&timeout=0", auth=AUTH) # check status # if response.status_code == HTTP_NOT_FOUND: @@ -165,6 +165,7 @@ if __name__ == "__main__": dispatch_uuid = entry["uuid"] method = entry["method"] message = entry["message"] + title = entry.get("title") # method dependent fields # phone = entry.get("phone") @@ -175,7 +176,8 @@ if __name__ == "__main__": pass elif method == "ntfy": user_topic = ntfy_api_get_topic(ntfy_api_server, ntfy_api_token, user) - ntfy_send(dispatch_uuid, user_topic, message, ntfy_push_target, ntfy_user, ntfy_pass) + ntfy_send(dispatch_uuid, user_topic, title, message, + ntfy_push_target, ntfy_user, ntfy_pass) elif method == "email": email_send(dispatch_uuid, email_address, message, smtp_target, smtp_user, smtp_pass) elif method == "debug": diff --git a/server/interface.py b/server/interface.py index 44b6525..2f4dcff 100755 --- a/server/interface.py +++ b/server/interface.py @@ -192,6 +192,7 @@ def smart_send_to_clients(): users = instructions.get("users") groups = instructions.get("groups") message = instructions.get("msg") + title = instructions.get("title") method = instructions.get("method") # allow single use string instead of array # @@ -212,11 +213,11 @@ def smart_send_to_clients(): else: persons = ldaptools.select_targets(users, groups, app.config["LDAP_ARGS"]) - dispatch_secrets = save_in_dispatch_queue(persons, message, method) + dispatch_secrets = save_in_dispatch_queue(persons, title, message, method) return flask.jsonify(dispatch_secrets) -def save_in_dispatch_queue(persons, message, method): +def save_in_dispatch_queue(persons, title, message, method): dispatch_secrets = [] @@ -237,6 +238,7 @@ def save_in_dispatch_queue(persons, message, method): method=method or master_method, timestamp=datetime.datetime.now().timestamp(), dispatch_secret=dispatch_secret, + title=title, message=message) db.session.merge(obj) From d6a2f8ec15a91a0bef65d1d6e3a01c2662dcee47 Mon Sep 17 00:00:00 2001 From: Yannik Schmidt Date: Sat, 17 Feb 2024 17:03:14 +0100 Subject: [PATCH 6/9] feat: add loop support for container --- client/dispatch-query.py | 87 ++++++++++++++++++++++------------------ 1 file changed, 49 insertions(+), 38 deletions(-) diff --git a/client/dispatch-query.py b/client/dispatch-query.py index b192ab5..d23c142 100755 --- a/client/dispatch-query.py +++ b/client/dispatch-query.py @@ -1,6 +1,7 @@ #!/usr/bin/python3 import sys +import time import argparse import subprocess import os @@ -121,6 +122,8 @@ if __name__ == "__main__": parser.add_argument('--smtp-user') parser.add_argument('--smtp-pass') + parser.add_argument('--loop', default=True, action=argparse.BooleanOptionalAction) + args = parser.parse_args() # set dispatch server & authentication # @@ -142,50 +145,58 @@ if __name__ == "__main__": smtp_user = args.smtp_user or os.environ.get("SMTP_USER") smtp_pass = args.smtp_pass or os.environ.get("SMTP_PASS") - # request dispatches # - response = requests.get(args.dispatch_server + "/get-dispatch?method=all&timeout=0", auth=AUTH) + first_run = True + while args.loop or first_run: - # check status # - if response.status_code == HTTP_NOT_FOUND: - sys.exit(0) + # request dispatches # + response = requests.get(args.dispatch_server + "/get-dispatch?method=all&timeout=0", auth=AUTH) - # fallback check for status # - response.raise_for_status() + # check status # + if response.status_code == HTTP_NOT_FOUND: + sys.exit(0) - # track dispatches that were confirmed to avoid duplicate confirmation # - dispatch_confirmed = [] + # fallback check for status # + response.raise_for_status() - # track failed dispatches # - errors = dict() + # track dispatches that were confirmed to avoid duplicate confirmation # + dispatch_confirmed = [] - # iterate over dispatch requests # - for entry in response.json(): + # track failed dispatches # + errors = dict() - user = entry["username"] - dispatch_uuid = entry["uuid"] - method = entry["method"] - message = entry["message"] - title = entry.get("title") + # iterate over dispatch requests # + for entry in response.json(): - # method dependent fields # - phone = entry.get("phone") - email_address = entry.get("email") + user = entry["username"] + dispatch_uuid = entry["uuid"] + method = entry["method"] + message = entry["message"] + title = entry.get("title") - # send message # - if method == "signal": - pass - elif method == "ntfy": - user_topic = ntfy_api_get_topic(ntfy_api_server, ntfy_api_token, user) - ntfy_send(dispatch_uuid, user_topic, title, message, - ntfy_push_target, ntfy_user, ntfy_pass) - elif method == "email": - email_send(dispatch_uuid, email_address, message, smtp_target, smtp_user, smtp_pass) - elif method == "debug": - debug_send(dispatch_uuid, entry) - elif method == "debug-fail": - debug_send(dispatch_uuid, entry, fail_it=True) - else: - print("Unsupported dispatch method {}".format(entry["method"]), sys=sys.stderr) - continue + # method dependent fields # + phone = entry.get("phone") + email_address = entry.get("email") - sys.exit(0) + # send message # + if method == "signal": + pass + elif method == "ntfy": + user_topic = ntfy_api_get_topic(ntfy_api_server, ntfy_api_token, user) + ntfy_send(dispatch_uuid, user_topic, title, message, + ntfy_push_target, ntfy_user, ntfy_pass) + elif method == "email": + email_send(dispatch_uuid, email_address, message, smtp_target, smtp_user, smtp_pass) + elif method == "debug": + debug_send(dispatch_uuid, entry) + elif method == "debug-fail": + debug_send(dispatch_uuid, entry, fail_it=True) + else: + print("Unsupported dispatch method {}".format(entry["method"]), sys=sys.stderr) + continue + + # wait a moment # + if args.loop: + time.sleep(5) + + # handle non-loop runs # + first_run = False From a4a868e899e05561e40253f5cdc27aed0e46da3a Mon Sep 17 00:00:00 2001 From: Yannik Schmidt Date: Sat, 17 Feb 2024 17:03:23 +0100 Subject: [PATCH 7/9] feat: add docker build --- client/Dockerfile | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 client/Dockerfile diff --git a/client/Dockerfile b/client/Dockerfile new file mode 100644 index 0000000..e1944b9 --- /dev/null +++ b/client/Dockerfile @@ -0,0 +1,9 @@ +FROM alpine + +WORKDIR /app/ +RUN apk --update --no-cache add python3 py3-requests + +COPY ./*.py ./ + +ENTRYPOINT ["python"] +CMD ["dispatch-query.py"] From 6b8e517e3c61fec81e2c74c17e78a663860e4c37 Mon Sep 17 00:00:00 2001 From: Yannik Schmidt Date: Sat, 17 Feb 2024 17:10:02 +0100 Subject: [PATCH 8/9] fix: migrate to alpine build --- server/Dockerfile | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/server/Dockerfile b/server/Dockerfile index 390224a..53baf46 100644 --- a/server/Dockerfile +++ b/server/Dockerfile @@ -1,19 +1,16 @@ -FROM python:3.9-slim-buster +FROM alpine -RUN apt update -RUN apt install python3-pip -y -RUN apt install libsasl2-dev python-dev libldap2-dev libssl-dev -y -RUN python3 -m pip install --upgrade pip -RUN apt install curl -y -RUN apt autoremove -y -RUN apt clean +RUN apk add --update --no-cache python3 py3-pip py3-ldap WORKDIR /app -RUN python3 -m pip install waitress +RUN python3 -m pip install --no-cache-dir --break-system-packages waitress COPY req.txt . -RUN python3 -m pip install --no-cache-dir -r req.txt + +# remove python-ldap (installed via apk) # +RUN sed -i '/^python-ldap.*$/d' req.txt +RUN python3 -m pip install --no-cache-dir --break-system-packages -r req.txt # precreate database directory for mount (will otherwise be created at before_first_request) COPY ./ . From c2853af6b48219c12930131aa2156cea4f00a938 Mon Sep 17 00:00:00 2001 From: Yannik Schmidt Date: Sat, 17 Feb 2024 17:11:34 +0100 Subject: [PATCH 9/9] fix: update to new docker build --- .github/workflows/main.yaml | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/.github/workflows/main.yaml b/.github/workflows/main.yaml index c71ef4d..50c4b32 100644 --- a/.github/workflows/main.yaml +++ b/.github/workflows/main.yaml @@ -29,10 +29,18 @@ jobs: username: ${{ secrets.REGISTRY_USER }} password: ${{ secrets.REGISTRY_PASS }} - - name: Build and push signal-event-dispatcher + name: Build and push event-dispatcher uses: docker/build-push-action@v3 with: - context: . + context: ./server/ platforms: linux/amd64 push: true tags: "${{ secrets.REGISTRY }}/athq/event-dispatcher:latest" + - + name: Build and push event-dispatcher + uses: docker/build-push-action@v3 + with: + context: ./client/ + platforms: linux/amd64 + push: true + tags: "${{ secrets.REGISTRY }}/athq/event-dispatcher-worker:latest"