diff --git a/intake/app.py b/intake/app.py index 8329a53..2ab7b82 100644 --- a/intake/app.py +++ b/intake/app.py @@ -1,5 +1,6 @@ from datetime import datetime, timedelta from pathlib import Path +import json import os import time @@ -34,7 +35,7 @@ def datetimeformat(value): return dt.strftime("%Y-%m-%d %H:%M:%S") -@app.route("/") +@app.get("/") def root(): """ Navigation home page. @@ -52,7 +53,7 @@ def root(): ) -@app.route("/source/") +@app.get("/source/") def source_feed(source_name): """ Feed view for a single source. @@ -146,6 +147,66 @@ def action(source_name, item_id, action): return jsonify(item) +@app.route("/edit/source/", methods=["GET", "POST"]) +def source_edit(source_name): + """ + Config editor for a source + """ + source = LocalSource(intake_data_dir(), source_name) + if not source.source_path.exists(): + abort(404) + + # For POST, check if the config is valid + error_message: str = None + if request.method == "POST": + config_str = request.form.get("config", "") + error_message, config = try_parse_config(config_str) + print(config_str) + print(error_message) + print(config) + if not error_message: + source.save_config(config) + return redirect(url_for("root")) + + # For GET, load the config + if request.method == "GET": + config = source.get_config() + config_str = json.dumps(config, indent=2) + + return render_template( + "edit.jinja2", + source=source, + config=config_str, + error_message=error_message, + ) + + +def try_parse_config(config_str: str): + if not config_str: + return ("Config required", {}) + try: + parsed = json.loads(config_str) + except json.JSONDecodeError: + return ("Invalid JSON", {}) + if not isinstance(parsed, dict): + return ("Invalid config format", {}) + if "action" not in parsed: + return ("No actions defined", {}) + action = parsed["action"] + if "fetch" not in action: + return ("No fetch action defined", {}) + fetch = action["fetch"] + if "exe" not in fetch: + return ("No fetch exe", {}) + return ( + None, + { + "action": parsed["action"], + "env": parsed["env"], + }, + ) + + def wsgi(): # init_default_logging() return app diff --git a/intake/source.py b/intake/source.py index 659c377..931a4b4 100755 --- a/intake/source.py +++ b/intake/source.py @@ -26,6 +26,13 @@ class LocalSource: with open(config_path, "r", encoding="utf8") as config_file: return json.load(config_file) + def save_config(self, config: dict) -> None: + config_path = self.source_path / "intake.json" + tmp_path = config_path.with_name(f"{config_path.name}.tmp") + with tmp_path.open("w") as f: + f.write(json.dumps(config, indent=2)) + os.rename(tmp_path, config_path) + def get_state_path(self) -> Path: return (self.source_path / "state").absolute() @@ -61,10 +68,11 @@ class LocalSource: def save_item(self, item: dict) -> None: # Write to a tempfile first to avoid losing the item on write failure - tmp_path = self.source_path / f"{item['id']}.item.tmp" + item_path = self.get_item_path(item["id"]) + tmp_path = item_path.with_name(f"{item_path.name}.tmp") with tmp_path.open("w") as f: f.write(json.dumps(item, indent=2)) - os.rename(tmp_path, self.get_item_path(item["id"])) + os.rename(tmp_path, item_path) def delete_item(self, item_id) -> None: os.remove(self.get_item_path(item_id)) diff --git a/intake/templates/edit.jinja2 b/intake/templates/edit.jinja2 new file mode 100644 index 0000000..56e2a85 --- /dev/null +++ b/intake/templates/edit.jinja2 @@ -0,0 +1,79 @@ + + + +Intake - {{ source.source_name }} + + + + +
+ +
+
+ + +

+
+
+ +
+ + diff --git a/intake/templates/feed.jinja2 b/intake/templates/feed.jinja2 index b0b6386..afc8714 100644 --- a/intake/templates/feed.jinja2 +++ b/intake/templates/feed.jinja2 @@ -178,13 +178,11 @@ var doAction = function (source, itemid, action) { {% endif %} -{% if items %}
-{% endif %} {# if items #} {% else %} diff --git a/intake/templates/home.jinja2 b/intake/templates/home.jinja2 index 297c60f..f4ada70 100644 --- a/intake/templates/home.jinja2 +++ b/intake/templates/home.jinja2 @@ -40,11 +40,12 @@ summary:focus {

No sources found.

{% else %} {% for source in sources %} -

{{ source.source_name|safe }}

+

{{ source.source_name|safe }} (edit)

{% endfor %} {% endif %} + diff --git a/tests/demo_basic_callback/increment.py b/tests/demo_basic_callback/increment.py index 5954bc0..b82a1ba 100755 --- a/tests/demo_basic_callback/increment.py +++ b/tests/demo_basic_callback/increment.py @@ -11,6 +11,7 @@ print("args:", args, file=sys.stderr, flush=True) if args.action == "fetch": print(json.dumps({ "id": "updateme", + "title": "The count is at 1", "action": { "increment": 1 } @@ -21,5 +22,6 @@ if args.action == "increment": item = json.loads(item) item["action"]["increment"] += 1 item["body"] = f"

{item['action']['increment']}

" + item["title"] = f"The count is at {item['action']['increment']}" print(json.dumps(item)) pass diff --git a/tests/demo_logging/intake.json b/tests/demo_logging/intake.json index 11935be..20675ed 100644 --- a/tests/demo_logging/intake.json +++ b/tests/demo_logging/intake.json @@ -2,7 +2,9 @@ "action": { "fetch": { "exe": "python3", - "args": ["update.py"] + "args": [ + "update.py" + ] } }, "env": {