apply some fixes for forgejo

This commit is contained in:
James Ravenscroft 2024-11-16 14:31:21 +00:00
parent 7e9aa77769
commit 11ffbbbb7b
2 changed files with 53 additions and 66 deletions

View File

@ -76,7 +76,6 @@ def create_app():
def authed_endpoint(f): def authed_endpoint(f):
@functools.wraps(f) @functools.wraps(f)
def wrapper(*args, **kwargs): def wrapper(*args, **kwargs):
authtok = request.headers.get("Authorization") authtok = request.headers.get("Authorization")
if authtok is None: if authtok is None:
@ -121,10 +120,12 @@ def process_photo_url(
doc["photo"] = [doc["photo"]] doc["photo"] = [doc["photo"]]
for i, photo in enumerate(doc["photo"]): for i, photo in enumerate(doc["photo"]):
if isinstance(photo, str): if isinstance(photo, str):
photo = {"url": photo, "alt": ""} photo = {"url": photo, "alt": ""}
elif "value" in photo:
photo["url"] = photo["value"]
if os.environ.get("MICROPUB_IMAGE_STRATEGY") == "copy": if os.environ.get("MICROPUB_IMAGE_STRATEGY") == "copy":
# download the photo # download the photo
@ -166,7 +167,6 @@ def process_photo_upload(created_at: datetime, file: FileStorage, suffix: str =
now_ts = int(time.mktime(created_at.timetuple())) now_ts = int(time.mktime(created_at.timetuple()))
if os.environ.get("MICROPUB_IMAGE_STRATEGY") == "copy": if os.environ.get("MICROPUB_IMAGE_STRATEGY") == "copy":
file.mimetype file.mimetype
ext = os.path.splitext(file.filename)[1] ext = os.path.splitext(file.filename)[1]
@ -199,7 +199,6 @@ def process_photo_upload(created_at: datetime, file: FileStorage, suffix: str =
def init_frontmatter(created_at: datetime, post_type: str, name: Optional[str] = None): def init_frontmatter(created_at: datetime, post_type: str, name: Optional[str] = None):
now_ts = int(time.mktime(created_at.timetuple())) now_ts = int(time.mktime(created_at.timetuple()))
if name: if name:
@ -269,7 +268,6 @@ def detect_entry_type(doc: dict) -> str:
def capture_frontmatter_props( def capture_frontmatter_props(
doc: Dict[str, Union[str, List[str]]], frontmatter: Dict[str, Union[str, List[str]]] doc: Dict[str, Union[str, List[str]]], frontmatter: Dict[str, Union[str, List[str]]]
): ):
keys = [ keys = [
"summary", "summary",
"bookmark-of", "bookmark-of",
@ -286,13 +284,9 @@ def capture_frontmatter_props(
keys += [f"u-{key}" for key in keys] keys += [f"u-{key}" for key in keys]
for key in keys: for key in keys:
if key in doc: if key in doc:
if isinstance(doc[key], dict) and ("type" in doc[key]): if isinstance(doc[key], dict) and ("type" in doc[key]):
if doc[key]["type"][0] == "h-cite": if doc[key]["type"][0] == "h-cite":
if "citations" not in frontmatter: if "citations" not in frontmatter:
frontmatter["citations"] = [] frontmatter["citations"] = []
frontmatter["citations"].append(doc[key]["properties"]) frontmatter["citations"].append(doc[key]["properties"])
@ -337,7 +331,6 @@ def process_multipart_post():
frontmatter["title"] = doc["name"] frontmatter["title"] = doc["name"]
if ("photo" in doc) or ("photo" in request.files) or ("photo[]" in request.files): if ("photo" in doc) or ("photo" in request.files) or ("photo[]" in request.files):
frontmatter["photo"] = [] frontmatter["photo"] = []
if "photo[]" in request.files: if "photo[]" in request.files:
@ -358,7 +351,6 @@ def process_multipart_post():
docstr += f"\n\n {doc['content']}" docstr += f"\n\n {doc['content']}"
else: else:
if "photo" in doc: if "photo" in doc:
photo_objects = process_photo_url(now, doc) photo_objects = process_photo_url(now, doc)
@ -394,14 +386,12 @@ def process_multipart_post():
def process_image_alt_texts(doc): def process_image_alt_texts(doc):
alts = [] alts = []
if isinstance(doc["photo"], str): if isinstance(doc["photo"], str):
doc["photo"] = [doc["photo"]] doc["photo"] = [doc["photo"]]
for i, photo in enumerate(doc["photo"]): for i, photo in enumerate(doc["photo"]):
if isinstance(photo, dict): if isinstance(photo, dict):
alts.append(doc["alt"]) alts.append(doc["alt"])
else: else:
@ -423,7 +413,6 @@ def process_json_post():
entry_type = detect_entry_type(props) entry_type = detect_entry_type(props)
if "published" in props: if "published" in props:
from dateutil import parser from dateutil import parser
now = parser.parse(props["published"][0]) now = parser.parse(props["published"][0])
@ -440,7 +429,6 @@ def process_json_post():
docstr = "" docstr = ""
if "photo" in props: if "photo" in props:
photo_objects = process_photo_url(now, props) photo_objects = process_photo_url(now, props)
frontmatter["photo"] = [ frontmatter["photo"] = [
@ -452,7 +440,6 @@ def process_json_post():
# docstr += f'<img src="{photo[0]}" alt="{photo[1]}" class="u-photo" /> \n\n' # docstr += f'<img src="{photo[0]}" alt="{photo[1]}" class="u-photo" /> \n\n'
for content in props.get("content", []): for content in props.get("content", []):
if isinstance(content, dict): if isinstance(content, dict):
if "html" in content: if "html" in content:
docstr += f"\n\n {content.get('html')}" docstr += f"\n\n {content.get('html')}"
@ -478,7 +465,6 @@ def get_api_client() -> forgejo.RepositoryApi:
@core_bp.route("/", methods=["POST"]) @core_bp.route("/", methods=["POST"])
@authed_endpoint @authed_endpoint
def req(): def req():
if request.get_json(): if request.get_json():
docstr, frontmatter, file_path = process_json_post() docstr, frontmatter, file_path = process_json_post()
else: else:
@ -504,13 +490,11 @@ def req():
return Response(status=202, headers={"Location": frontmatter["url"]}) return Response(status=202, headers={"Location": frontmatter["url"]})
except Exception as e: except Exception as e:
logger.error(e, exc_info=True) logger.error(e, exc_info=True)
return {"error": str(e)}, 500 return {"error": str(e)}, 500
def parse_categories(): def parse_categories():
strategy = os.environ.get("MICROPUB_CATEGORY_LIST_STRATEGY") strategy = os.environ.get("MICROPUB_CATEGORY_LIST_STRATEGY")
if strategy == "feed": if strategy == "feed":
@ -521,12 +505,10 @@ def parse_categories():
def get_syndication_targets(): def get_syndication_targets():
targets = os.environ.get("SYNDICATION_TARGETS", "").split(",") targets = os.environ.get("SYNDICATION_TARGETS", "").split(",")
defs = [] defs = []
for target in targets: for target in targets:
if os.environ.get(f"SYNDICATION_TARGET_{target}_URL") is None: if os.environ.get(f"SYNDICATION_TARGET_{target}_URL") is None:
print(f"No url for SYNDICATION_TARGET_{target}_URL") print(f"No url for SYNDICATION_TARGET_{target}_URL")
continue continue
@ -543,7 +525,6 @@ def get_syndication_targets():
@core_bp.route("/media", methods=["POST"]) @core_bp.route("/media", methods=["POST"])
@authed_endpoint @authed_endpoint
def media_endpoint(): def media_endpoint():
now = datetime.now() now = datetime.now()
url = process_photo_upload(now, request.files["file"]) url = process_photo_upload(now, request.files["file"])
@ -551,7 +532,6 @@ def media_endpoint():
def generate_config_json(): def generate_config_json():
return { return {
"media-endpoint": os.environ.get(f"MICROCOSM_BASE_URL", request.base_url) "media-endpoint": os.environ.get(f"MICROCOSM_BASE_URL", request.base_url)
+ "media", + "media",
@ -570,7 +550,6 @@ def generate_config_json():
@core_bp.route("/", methods=["GET"]) @core_bp.route("/", methods=["GET"])
@authed_endpoint @authed_endpoint
def index(): def index():
if request.args.get("q") == "config": if request.args.get("q") == "config":
return generate_config_json() return generate_config_json()

View File

@ -3,6 +3,8 @@ import base64
import giteapy import giteapy
import os import os
import clientapi_forgejo as forgejo
from flask import request, Blueprint from flask import request, Blueprint
from urllib.parse import urlparse from urllib.parse import urlparse
@ -11,13 +13,10 @@ from datetime import datetime
webhook_bp = Blueprint("webmention", __name__) webhook_bp = Blueprint("webmention", __name__)
@webhook_bp.route("/webmentions", methods=["POST"])
@webhook_bp.route("/webmentions", methods=['POST'])
def webmention_hook(): def webmention_hook():
"""Accept web mention webhook request""" """Accept web mention webhook request"""
body = request.get_json() body = request.get_json()
print(f"Incoming webmention {body}") print(f"Incoming webmention {body}")
@ -27,7 +26,7 @@ def webmention_hook():
return {"error": "invalid_request"}, 400 return {"error": "invalid_request"}, 400
# assert that secret matches # assert that secret matches
if body.get('secret') != os.environ.get("WEBMENTION_SECRET", "changeme"): if body.get("secret") != os.environ.get("WEBMENTION_SECRET", "changeme"):
return {"error": "invalid_secret"}, 401 return {"error": "invalid_secret"}, 401
# get existing mentions from gitea # get existing mentions from gitea
@ -37,22 +36,24 @@ def webmention_hook():
old_sha = None old_sha = None
try: try:
mentions_meta = api.repo_get_contents(os.environ.get('GITEA_REPO_OWNER'), mentions_meta = api.repo_get_contents(
os.environ.get('GITEA_REPO_NAME'), os.environ.get('WEBMENTIONS_JSON_FILE')) os.environ.get("GITEA_REPO_OWNER"),
os.environ.get("GITEA_REPO_NAME"),
os.environ.get("WEBMENTIONS_JSON_FILE"),
)
old_sha = mentions_meta.sha old_sha = mentions_meta.sha
mentions = json.loads(base64.decodebytes(mentions_meta.content.encode('utf8'))) mentions = json.loads(base64.decodebytes(mentions_meta.content.encode("utf8")))
except giteapy.rest.ApiException as e: except forgejo.rest.ApiException as e:
if e.status == 404: if e.status == 404:
print("no mentions yet, create new mentions file") print("no mentions yet, create new mentions file")
mentions = {} mentions = {}
# parse target url and get path on server # parse target url and get path on server
url_path = urlparse(body.get('target')).path url_path = urlparse(body.get("target")).path
# create mention entry if needed # create mention entry if needed
if url_path not in mentions: if url_path not in mentions:
@ -60,7 +61,7 @@ def webmention_hook():
# if the mention is already processed, do nothing. # if the mention is already processed, do nothing.
for entry in mentions[url_path]: for entry in mentions[url_path]:
if entry['source'] == body['source']: if entry["source"] == body["source"]:
return {"message": "mention already processed, no action taken."} return {"message": "mention already processed, no action taken."}
activity_types = { activity_types = {
@ -69,39 +70,42 @@ def webmention_hook():
"repost-of": "repost", "repost-of": "repost",
"bookmark-of": "bookmark", "bookmark-of": "bookmark",
"mention-of": "mention", "mention-of": "mention",
"rsvp":"rsvp" "rsvp": "rsvp",
} }
# format the mention like the data from webmention.io api # format the mention like the data from webmention.io api
new_mention = { new_mention = {
"id": body['post']['wm-id'], "id": body["post"]["wm-id"],
"source": body['source'], "source": body["source"],
"target": body['target'], "target": body["target"],
"activity":{ "activity": {"type": activity_types[body["post"]["wm-property"]]},
"type": activity_types[body['post']['wm-property']] "verified_date": body.get("wm-received", datetime.now().isoformat()),
},
"verified_date": body.get('wm-received', datetime.now().isoformat()),
"data": { "data": {
"author": body['post']['author'], "author": body["post"]["author"],
"content": body['post'].get('content',{}).get('html', None), "content": body["post"].get("content", {}).get("html", None),
"published": body['post'].get('published') "published": body["post"].get("published"),
} },
} }
# append the new mention # append the new mention
mentions[url_path].append(new_mention) mentions[url_path].append(new_mention)
content = base64.encodestring(json.dumps(mentions, indent=2).encode("utf8")).decode("utf8") content = base64.b64encode(json.dumps(mentions, indent=2).encode("utf8")).decode(
"utf8"
)
# store to repo # store to repo
if old_sha: if old_sha:
print(f"Update {os.environ.get('WEBMENTIONS_JSON_FILE')}") print(f"Update {os.environ.get('WEBMENTIONS_JSON_FILE')}")
body = giteapy.UpdateFileOptions(content=content, sha=old_sha) body = forgejo.UpdateFileOptions(content=content, sha=old_sha)
try: try:
r = api.repo_update_file(os.environ.get( r = api.repo_update_file(
'GITEA_REPO_OWNER'), os.environ.get('GITEA_REPO_NAME'), os.environ.get('WEBMENTIONS_JSON_FILE'), body) os.environ.get("GITEA_REPO_OWNER"),
os.environ.get("GITEA_REPO_NAME"),
os.environ.get("WEBMENTIONS_JSON_FILE"),
body,
)
return {"message": "ok"} return {"message": "ok"}
@ -113,8 +117,12 @@ def webmention_hook():
body = giteapy.CreateFileOptions(content=content) body = giteapy.CreateFileOptions(content=content)
try: try:
r = api.repo_create_file(os.environ.get( r = api.repo_create_file(
'GITEA_REPO_OWNER'), os.environ.get('GITEA_REPO_NAME'), os.environ.get('WEBMENTIONS_JSON_FILE'), body) os.environ.get("GITEA_REPO_OWNER"),
os.environ.get("GITEA_REPO_NAME"),
os.environ.get("WEBMENTIONS_JSON_FILE"),
body,
)
return {"message": "ok"} return {"message": "ok"}