Micropub tweaks

main
Thomas Sileo 2022-07-17 20:43:03 +02:00
parent 6f25d06bbb
commit 88ca8a676d
3 changed files with 76 additions and 9 deletions

View File

@ -5,6 +5,7 @@ from fastapi import Depends
from fastapi import Request
from fastapi.responses import JSONResponse
from fastapi.responses import RedirectResponse
from loguru import logger
from app import activitypub as ap
from app.boxes import get_outbox_object_by_ap_id
@ -55,6 +56,14 @@ async def micropub_endpoint(
return {}
def _prop_get(dat: dict[str, Any], key: str) -> str:
val = dat[key]
if isinstance(val, list):
return val[0]
else:
return val
@router.post("/micropub")
async def post_micropub_endpoint(
request: Request,
@ -62,8 +71,17 @@ async def post_micropub_endpoint(
db_session: AsyncSession = Depends(get_db_session),
) -> RedirectResponse | JSONResponse:
form_data = await request.form()
is_json = False
if not form_data:
form_data = await request.json()
is_json = True
insufficient_scope_resp = JSONResponse(
status_code=401, content={"error": "insufficient_scope"}
)
if "action" in form_data:
if form_data["action"] == "delete":
if form_data["action"] in ["delete", "update"]:
outbox_object = await get_outbox_object_by_ap_id(
db_session, form_data["url"]
)
@ -75,14 +93,48 @@ async def post_micropub_endpoint(
},
status_code=400,
)
if form_data["action"] == "delete":
if "delete" not in access_token_info.scopes:
return insufficient_scope_resp
logger.info(f"Deleting object {outbox_object.ap_id}")
await send_delete(db_session, outbox_object.ap_id) # type: ignore
return JSONResponse(content={}, status_code=200)
elif form_data["action"] == "update":
if "update" not in access_token_info.scopes:
return insufficient_scope_resp
# TODO(ts): support update
# "replace": {"content": ["new content"]}
logger.info(f"Updating object {outbox_object.ap_id}: {form_data}")
return JSONResponse(content={}, status_code=200)
else:
raise ValueError("Should never happen")
else:
return JSONResponse(
content={
"error": "invalid_request",
"error_description": f'Unsupported action: {form_data["action"]}',
},
status_code=400,
)
if "create" not in access_token_info.scopes:
return insufficient_scope_resp
if is_json:
entry_type = _prop_get(form_data, "type") # type: ignore
else:
h = "entry"
if "h" in form_data:
h = form_data["h"]
entry_type = f"h-{h}"
if h != "entry":
logger.info(f"Creating {entry_type}")
if entry_type != "h-entry":
return JSONResponse(
content={
"error": "invalid_request",
@ -91,7 +143,13 @@ async def post_micropub_endpoint(
status_code=400,
)
# TODO(ts): support creating Article (with a name)
if is_json:
content = _prop_get(form_data["properties"], "content") # type: ignore
else:
content = form_data["content"]
public_id = await send_create(
db_session,
content,

View File

@ -11,7 +11,7 @@
<div style="flex:1;">
<div style="margin-top:20px">
<a class="lcolor" style="font-size:1.2em;font-weight:600;text-decoration:none;" href="{{ client.url }}">{{ client.name }}</a>
<p>wants you to login as <strong class="lcolor">{{ me }}</strong></p>
<p>wants you to login as <strong class="lcolor">{{ me }}</strong> with the following redirect URI: <code>{{ redirect_uri }}</code>.</p>
</div>
</div>
</div>

View File

@ -1,5 +1,6 @@
from dataclasses import dataclass
from typing import Any
from urllib.parse import urlparse
from app.utils import microformats
from app.utils.url import make_abs
@ -22,6 +23,14 @@ def _get_prop(props: dict[str, Any], name: str, default=None) -> Any:
async def get_client_id_data(url: str) -> IndieAuthClient | None:
# Don't fetch localhost URL
if urlparse(url).netloc == "localhost":
return IndieAuthClient(
logo=None,
name=url,
url=url,
)
maybe_data_and_html = await microformats.fetch_and_parse(url)
if maybe_data_and_html is not None:
data: dict[str, Any] = maybe_data_and_html[0]