apply some fixes for forgejo
This commit is contained in:
parent
7e9aa77769
commit
11ffbbbb7b
|
@ -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()
|
||||||
|
|
||||||
|
|
|
@ -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"}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue