diff --git a/README.md b/README.md index d4f89ea..5ee8d33 100644 --- a/README.md +++ b/README.md @@ -88,11 +88,18 @@ string in a production environment. `TXL_LOGLEVEL`: Logging level. Use Python notation. The default is `WARN`. -`TXL_SMTP_HOST`: SMTP host to send feedback messages through. If not defined, -the feedback form will not be shown in the UI. +`TXL_SMTP_HOST`: SMTP host to send feedback messages through. `TXL_SMTP_PORT`: Port of the SMTP server. Defaults to `1025`. +`TXL_FEEDBACK_PATH`: if a SMTP server is not available, the feedback message +may be written to a file under this given path for further processing. The file +will have a random name and a `.txt` suffix. This option is only available if +`TXL_SMTP_HOST` is not defined. If neither `TXL_SMTP_HOST` nor +`TXL_FEEDBACK_PATH` is defined, the feedback form will not be shown in the UI +and a POST request to the `/feedback` REST endpoint will result in a `501 Not +Implemented` error. + ## Web UI diff --git a/scriptshifter/__init__.py b/scriptshifter/__init__.py index ea5aef5..88903f2 100644 --- a/scriptshifter/__init__.py +++ b/scriptshifter/__init__.py @@ -22,10 +22,21 @@ messages, run: `python -m smtpd -n -c DebuggingServer localhost:1025` and set SMTP_HOST to "localhost". -The default is None in which causes the feedback form to be disabled. +The default is None which causes the feedback form to be disabled. """ SMTP_HOST = environ.get("TXL_SMTP_HOST") +""" +Folder path for the serialized feedback form. + +The feedback message shall be written to this folder as a text file for further +processing in case a SMTP server is not available. The file name will have +a unique random name. + +This only takes effect if SMTP_HOST is not set. +""" +FEEDBACK_PATH = environ.get("TXL_FEEDBACK_PATH") + with open(path.join(path.dirname(APP_ROOT), "VERSION")) as fh: version_info = fh.readlines() GIT_TAG = version_info[0].strip() @@ -39,13 +50,20 @@ if not env: logger.warn("No .env file found. Assuming env was passed externally.") -if SMTP_HOST: - try: - SMTP_PORT = int(environ.get("TXL_SMTP_PORT", "1025")) - except ValueError: - raise SystemError("TXL_SMTP_PORT env var is not an integer.") - EMAIL_FROM = environ["TXL_EMAIL_FROM"] - EMAIL_TO = environ["TXL_EMAIL_TO"] -else: - logger.warn("No SMTP host defined. Feedback form won't be available.") - SMTP_PORT = EMAIL_FROM = EMAIL_TO = None +EMAIL_FROM = environ["TXL_EMAIL_FROM"] +EMAIL_TO = environ["TXL_EMAIL_TO"] +try: + SMTP_PORT = int(environ.get("TXL_SMTP_PORT", "1025")) +except ValueError: + raise SystemError("TXL_SMTP_PORT env var is not an integer.") + +if not SMTP_HOST: + if FEEDBACK_PATH: + logger.info( + "No SMTP host defined. Feedback messages will be written " + f"to files under {FEEDBACK_PATH}.") + else: + logger.warn( + "No SMTP host or feedback message folder defined. " + "Feedback form won't be available.") + SMTP_PORT = EMAIL_FROM = EMAIL_TO = None diff --git a/scriptshifter/rest_api.py b/scriptshifter/rest_api.py index ad65419..197639f 100644 --- a/scriptshifter/rest_api.py +++ b/scriptshifter/rest_api.py @@ -2,9 +2,11 @@ from base64 import b64encode from email.message import EmailMessage +from email.generator import Generator from json import dumps from os import environ, urandom from smtplib import SMTP +from tempfile import NamedTemporaryFile from flask import Flask, jsonify, render_template, request from flask_cors import CORS @@ -12,7 +14,8 @@ from scriptshifter import ( EMAIL_FROM, EMAIL_TO, GIT_COMMIT, GIT_TAG, - SMTP_HOST, SMTP_PORT) + SMTP_HOST, SMTP_PORT, + FEEDBACK_PATH) from scriptshifter.exceptions import ApiError from scriptshifter.tables import list_tables, get_language from scriptshifter.trans import transliterate @@ -72,7 +75,7 @@ def index(): "index.html", languages=list_tables(), version_info=(GIT_TAG, GIT_COMMIT), - feedback_form=SMTP_HOST is not None) + feedback_form=SMTP_HOST is not None or FEEDBACK_PATH is not None) @app.route("/health", methods=["GET"]) @@ -132,6 +135,9 @@ def feedback(): """ Allows users to provide feedback to improve a specific result. """ + if not SMTP_HOST and not FEEDBACK_PATH: + return {"message": "Feedback form is not configured."}, 501 + t_dir = request.json.get("t_dir", "s2r") options = request.json.get("options", {}) contact = request.json.get("contact") @@ -155,10 +161,18 @@ def feedback(): *Notes:*\n {request.json['notes']}""") - # TODO This uses a test SMTP server: - # python -m smtpd -n -c DebuggingServer localhost:1025 - smtp = SMTP(SMTP_HOST, SMTP_PORT) - smtp.send_message(msg) - smtp.quit() + if SMTP_HOST: + # TODO This uses a test SMTP server: + # python -m smtpd -n -c DebuggingServer localhost:1025 + smtp = SMTP(SMTP_HOST, SMTP_PORT) + smtp.send_message(msg) + smtp.quit() + + else: + with NamedTemporaryFile( + suffix=".txt", dir=FEEDBACK_PATH, delete=False) as fh: + gen = Generator(fh) + gen.write(msg.as_bytes()) + logger.info(f"Feedback message generated at {fh.name}.") return {"message": "Feedback message sent."}