#!/usr/bin/python3 import argparse import html import subprocess import sys import tempfile import yaml import psycopg import requests from bs4 import BeautifulSoup ap = argparse.ArgumentParser() ap.add_argument("--author", default="hjp") ap.add_argument("--content_type", default="text/plain") ap.add_argument("--tags", nargs="+") g = ap.add_mutually_exclusive_group(required=True) g.add_argument("--content") g.add_argument("--url") g.add_argument("--file") g.add_argument("--editor", action="store_true") args = ap.parse_args() if args.content: content = args.content elif args.file: with open(args.file) as fh: content = fh.read() elif args.url: r = requests.get(args.url) if r.status_code != 200: print(f"GETting {args.url} failed with {r.status_code} {r.message}", file=sys.stderr) exit(1) soup = BeautifulSoup(r.content, "lxml") title = soup.find("title") title = title.text content = f"[{title}]({args.url})" args.content_type = "text/markdown" elif args.editor: with tempfile.NamedTemporaryFile(delete_on_close=False) as tfh: tfh.close() subprocess.run(["sensible-editor", tfh.name]) with open(tfh.name, "r") as fh: content = fh.read() if len(content) == 0: print("Content is empty. Aborting.", file=sys.stderr) conn = psycopg.connect(dbname="zettel") csr = conn.cursor(row_factory=psycopg.rows.namedtuple_row) csr.execute("select * from role where name = %s", (args.author,)) author_id = csr.fetchone().id csr.execute( """ insert into post(text, ts, content_type, author) values(%s, now(), %s, %s) returning id """, (content, args.content_type, author_id,)) post_id = csr.fetchone().id for tag in args.tags: csr.execute("select * from tag where lower(name) = lower(%s)", (tag,)) # XXX - use citext? r = csr.fetchone() if not r: csr.execute("insert into tag(name) values(%s) returning id", (tag,)) r = csr.fetchone() tag_id = r.id csr.execute("insert into tag_post(tag, post) values(%s, %s)", (tag_id, post_id,)) csr.execute("insert into acl(post, role) values(%s, %s)", (post_id, author_id,)) conn.commit()