mirror of
https://git.sr.ht/~tsileo/microblog.pub
synced 2024-12-22 13:14:28 +00:00
Micropub tweaks
This commit is contained in:
parent
6f25d06bbb
commit
88ca8a676d
3 changed files with 76 additions and 9 deletions
|
@ -5,6 +5,7 @@ from fastapi import Depends
|
||||||
from fastapi import Request
|
from fastapi import Request
|
||||||
from fastapi.responses import JSONResponse
|
from fastapi.responses import JSONResponse
|
||||||
from fastapi.responses import RedirectResponse
|
from fastapi.responses import RedirectResponse
|
||||||
|
from loguru import logger
|
||||||
|
|
||||||
from app import activitypub as ap
|
from app import activitypub as ap
|
||||||
from app.boxes import get_outbox_object_by_ap_id
|
from app.boxes import get_outbox_object_by_ap_id
|
||||||
|
@ -55,6 +56,14 @@ async def micropub_endpoint(
|
||||||
return {}
|
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")
|
@router.post("/micropub")
|
||||||
async def post_micropub_endpoint(
|
async def post_micropub_endpoint(
|
||||||
request: Request,
|
request: Request,
|
||||||
|
@ -62,8 +71,17 @@ async def post_micropub_endpoint(
|
||||||
db_session: AsyncSession = Depends(get_db_session),
|
db_session: AsyncSession = Depends(get_db_session),
|
||||||
) -> RedirectResponse | JSONResponse:
|
) -> RedirectResponse | JSONResponse:
|
||||||
form_data = await request.form()
|
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 "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(
|
outbox_object = await get_outbox_object_by_ap_id(
|
||||||
db_session, form_data["url"]
|
db_session, form_data["url"]
|
||||||
)
|
)
|
||||||
|
@ -75,14 +93,48 @@ async def post_micropub_endpoint(
|
||||||
},
|
},
|
||||||
status_code=400,
|
status_code=400,
|
||||||
)
|
)
|
||||||
await send_delete(db_session, outbox_object.ap_id) # type: ignore
|
|
||||||
return JSONResponse(content={}, status_code=200)
|
|
||||||
|
|
||||||
h = "entry"
|
if form_data["action"] == "delete":
|
||||||
if "h" in form_data:
|
if "delete" not in access_token_info.scopes:
|
||||||
h = form_data["h"]
|
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)
|
||||||
|
|
||||||
if h != "entry":
|
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}"
|
||||||
|
|
||||||
|
logger.info(f"Creating {entry_type}")
|
||||||
|
|
||||||
|
if entry_type != "h-entry":
|
||||||
return JSONResponse(
|
return JSONResponse(
|
||||||
content={
|
content={
|
||||||
"error": "invalid_request",
|
"error": "invalid_request",
|
||||||
|
@ -91,7 +143,13 @@ async def post_micropub_endpoint(
|
||||||
status_code=400,
|
status_code=400,
|
||||||
)
|
)
|
||||||
|
|
||||||
content = form_data["content"]
|
# 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(
|
public_id = await send_create(
|
||||||
db_session,
|
db_session,
|
||||||
content,
|
content,
|
||||||
|
|
|
@ -11,7 +11,7 @@
|
||||||
<div style="flex:1;">
|
<div style="flex:1;">
|
||||||
<div style="margin-top:20px">
|
<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>
|
<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>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
from typing import Any
|
from typing import Any
|
||||||
|
from urllib.parse import urlparse
|
||||||
|
|
||||||
from app.utils import microformats
|
from app.utils import microformats
|
||||||
from app.utils.url import make_abs
|
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:
|
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)
|
maybe_data_and_html = await microformats.fetch_and_parse(url)
|
||||||
if maybe_data_and_html is not None:
|
if maybe_data_and_html is not None:
|
||||||
data: dict[str, Any] = maybe_data_and_html[0]
|
data: dict[str, Any] = maybe_data_and_html[0]
|
||||||
|
|
Loading…
Reference in a new issue