Allow to interact with objects via lookup
parent
d381bb3fec
commit
c711096262
22
app/admin.py
22
app/admin.py
|
@ -116,6 +116,16 @@ async def get_lookup(
|
||||||
db_session, [ap_object] # type: ignore
|
db_session, [ap_object] # type: ignore
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
|
# Check if the object is in the inbox
|
||||||
|
requested_object = await boxes.get_anybox_object_by_ap_id(
|
||||||
|
db_session, ap_object.ap_id
|
||||||
|
)
|
||||||
|
if requested_object:
|
||||||
|
return RedirectResponse(
|
||||||
|
request.url_for("admin_object") + f"?ap_id={ap_object.ap_id}",
|
||||||
|
status_code=302,
|
||||||
|
)
|
||||||
|
|
||||||
actors_metadata = await get_actors_metadata(
|
actors_metadata = await get_actors_metadata(
|
||||||
db_session, [ap_object.actor] # type: ignore
|
db_session, [ap_object.actor] # type: ignore
|
||||||
)
|
)
|
||||||
|
@ -148,6 +158,14 @@ async def admin_new(
|
||||||
in_reply_to_object = await boxes.get_anybox_object_by_ap_id(
|
in_reply_to_object = await boxes.get_anybox_object_by_ap_id(
|
||||||
db_session, in_reply_to
|
db_session, in_reply_to
|
||||||
)
|
)
|
||||||
|
if not in_reply_to_object:
|
||||||
|
logger.info(f"Saving unknwown object {in_reply_to}")
|
||||||
|
raw_object = await ap.fetch(in_reply_to)
|
||||||
|
await boxes.save_object_to_inbox(db_session, raw_object)
|
||||||
|
await db_session.commit()
|
||||||
|
in_reply_to_object = await boxes.get_anybox_object_by_ap_id(
|
||||||
|
db_session, in_reply_to
|
||||||
|
)
|
||||||
|
|
||||||
# Add mentions to the initial note content
|
# Add mentions to the initial note content
|
||||||
if not in_reply_to_object:
|
if not in_reply_to_object:
|
||||||
|
@ -891,7 +909,9 @@ async def admin_actions_bookmark(
|
||||||
) -> RedirectResponse:
|
) -> RedirectResponse:
|
||||||
inbox_object = await get_inbox_object_by_ap_id(db_session, ap_object_id)
|
inbox_object = await get_inbox_object_by_ap_id(db_session, ap_object_id)
|
||||||
if not inbox_object:
|
if not inbox_object:
|
||||||
raise ValueError("Should never happen")
|
logger.info(f"Saving unknwown object {ap_object_id}")
|
||||||
|
raw_object = await ap.fetch(ap_object_id)
|
||||||
|
inbox_object = await boxes.save_object_to_inbox(db_session, raw_object)
|
||||||
inbox_object.is_bookmarked = True
|
inbox_object.is_bookmarked = True
|
||||||
await db_session.commit()
|
await db_session.commit()
|
||||||
return RedirectResponse(redirect_url, status_code=302)
|
return RedirectResponse(redirect_url, status_code=302)
|
||||||
|
|
61
app/boxes.py
61
app/boxes.py
|
@ -128,7 +128,13 @@ async def send_delete(db_session: AsyncSession, ap_object_id: str) -> None:
|
||||||
async def send_like(db_session: AsyncSession, ap_object_id: str) -> None:
|
async def send_like(db_session: AsyncSession, ap_object_id: str) -> None:
|
||||||
inbox_object = await get_inbox_object_by_ap_id(db_session, ap_object_id)
|
inbox_object = await get_inbox_object_by_ap_id(db_session, ap_object_id)
|
||||||
if not inbox_object:
|
if not inbox_object:
|
||||||
raise ValueError(f"{ap_object_id} not found in the inbox")
|
logger.info(f"Saving unknwown object {ap_object_id}")
|
||||||
|
raw_object = await ap.fetch(ap.get_id(ap_object_id))
|
||||||
|
await save_object_to_inbox(db_session, raw_object)
|
||||||
|
await db_session.commit()
|
||||||
|
inbox_object = await get_inbox_object_by_ap_id(db_session, ap_object_id)
|
||||||
|
if not inbox_object:
|
||||||
|
raise ValueError("Should never happen")
|
||||||
|
|
||||||
like_id = allocate_outbox_id()
|
like_id = allocate_outbox_id()
|
||||||
like = {
|
like = {
|
||||||
|
@ -155,7 +161,13 @@ async def send_like(db_session: AsyncSession, ap_object_id: str) -> None:
|
||||||
async def send_announce(db_session: AsyncSession, ap_object_id: str) -> None:
|
async def send_announce(db_session: AsyncSession, ap_object_id: str) -> None:
|
||||||
inbox_object = await get_inbox_object_by_ap_id(db_session, ap_object_id)
|
inbox_object = await get_inbox_object_by_ap_id(db_session, ap_object_id)
|
||||||
if not inbox_object:
|
if not inbox_object:
|
||||||
raise ValueError(f"{ap_object_id} not found in the inbox")
|
logger.info(f"Saving unknwown object {ap_object_id}")
|
||||||
|
raw_object = await ap.fetch(ap.get_id(ap_object_id))
|
||||||
|
await save_object_to_inbox(db_session, raw_object)
|
||||||
|
await db_session.commit()
|
||||||
|
inbox_object = await get_inbox_object_by_ap_id(db_session, ap_object_id)
|
||||||
|
if not inbox_object:
|
||||||
|
raise ValueError("Should never happen")
|
||||||
|
|
||||||
if inbox_object.visibility not in [
|
if inbox_object.visibility not in [
|
||||||
ap.VisibilityEnum.PUBLIC,
|
ap.VisibilityEnum.PUBLIC,
|
||||||
|
@ -183,12 +195,13 @@ async def send_announce(db_session: AsyncSession, ap_object_id: str) -> None:
|
||||||
raise ValueError("Should never happen")
|
raise ValueError("Should never happen")
|
||||||
|
|
||||||
inbox_object.announced_via_outbox_object_ap_id = outbox_object.ap_id
|
inbox_object.announced_via_outbox_object_ap_id = outbox_object.ap_id
|
||||||
await db_session.commit()
|
|
||||||
|
|
||||||
recipients = await _compute_recipients(db_session, announce)
|
recipients = await _compute_recipients(db_session, announce)
|
||||||
for rcp in recipients:
|
for rcp in recipients:
|
||||||
await new_outgoing_activity(db_session, rcp, outbox_object.id)
|
await new_outgoing_activity(db_session, rcp, outbox_object.id)
|
||||||
|
|
||||||
|
await db_session.commit()
|
||||||
|
|
||||||
|
|
||||||
async def send_follow(db_session: AsyncSession, ap_actor_id: str) -> None:
|
async def send_follow(db_session: AsyncSession, ap_actor_id: str) -> None:
|
||||||
actor = await fetch_actor(db_session, ap_actor_id)
|
actor = await fetch_actor(db_session, ap_actor_id)
|
||||||
|
@ -300,6 +313,12 @@ async def fetch_conversation_root(
|
||||||
obj: AnyboxObject | RemoteObject,
|
obj: AnyboxObject | RemoteObject,
|
||||||
is_root: bool = False,
|
is_root: bool = False,
|
||||||
) -> str:
|
) -> str:
|
||||||
|
"""Some softwares do not set the context/conversation field (like Misskey).
|
||||||
|
This means we have to track conversation ourselves. To do set, we fetch
|
||||||
|
the root of the conversation and either:
|
||||||
|
- use the context field if set
|
||||||
|
- or build a custom conversation ID
|
||||||
|
"""
|
||||||
if not obj.in_reply_to or is_root:
|
if not obj.in_reply_to or is_root:
|
||||||
if obj.ap_context:
|
if obj.ap_context:
|
||||||
return obj.ap_context
|
return obj.ap_context
|
||||||
|
@ -1731,6 +1750,42 @@ async def save_to_inbox(
|
||||||
await db_session.commit()
|
await db_session.commit()
|
||||||
|
|
||||||
|
|
||||||
|
async def save_object_to_inbox(
|
||||||
|
db_session: AsyncSession,
|
||||||
|
raw_object: ap.RawObject,
|
||||||
|
) -> models.InboxObject:
|
||||||
|
obj_actor = await fetch_actor(db_session, ap.get_actor_id(raw_object))
|
||||||
|
|
||||||
|
ro = RemoteObject(raw_object, actor=obj_actor)
|
||||||
|
|
||||||
|
ap_published_at = now()
|
||||||
|
if "published" in ro.ap_object:
|
||||||
|
ap_published_at = parse_isoformat(ro.ap_object["published"])
|
||||||
|
|
||||||
|
inbox_object = models.InboxObject(
|
||||||
|
server=urlparse(ro.ap_id).hostname,
|
||||||
|
actor_id=obj_actor.id,
|
||||||
|
ap_actor_id=obj_actor.ap_id,
|
||||||
|
ap_type=ro.ap_type,
|
||||||
|
ap_id=ro.ap_id,
|
||||||
|
ap_context=ro.ap_context,
|
||||||
|
conversation=await fetch_conversation_root(db_session, ro),
|
||||||
|
ap_published_at=ap_published_at,
|
||||||
|
ap_object=ro.ap_object,
|
||||||
|
visibility=ro.visibility,
|
||||||
|
relates_to_inbox_object_id=None,
|
||||||
|
relates_to_outbox_object_id=None,
|
||||||
|
activity_object_ap_id=ro.activity_object_ap_id,
|
||||||
|
og_meta=await opengraph.og_meta_from_note(db_session, ro),
|
||||||
|
is_hidden_from_stream=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
db_session.add(inbox_object)
|
||||||
|
await db_session.flush()
|
||||||
|
await db_session.refresh(inbox_object)
|
||||||
|
return inbox_object
|
||||||
|
|
||||||
|
|
||||||
async def public_outbox_objects_count(db_session: AsyncSession) -> int:
|
async def public_outbox_objects_count(db_session: AsyncSession) -> int:
|
||||||
return await db_session.scalar(
|
return await db_session.scalar(
|
||||||
select(func.count(models.OutboxObject.id)).where(
|
select(func.count(models.OutboxObject.id)).where(
|
||||||
|
|
|
@ -76,12 +76,12 @@ _RESIZED_CACHE: MutableMapping[tuple[str, int], tuple[bytes, str, Any]] = LFUCac
|
||||||
# TODO(ts):
|
# TODO(ts):
|
||||||
#
|
#
|
||||||
# Next:
|
# Next:
|
||||||
|
# - empty recipients for Share on "was not in the inbox" object
|
||||||
# - support Move
|
# - support Move
|
||||||
# - support actor delete
|
# - support actor delete
|
||||||
# - allow to share old notes
|
# - allow to share old notes
|
||||||
# - allow to interact with object not in anybox (i.e. like from a lookup)
|
# - allow to interact with object not in anybox (i.e. like from a lookup)
|
||||||
# - only show 10 most recent threads in DMs
|
# - only show 10 most recent threads in DMs
|
||||||
# - custom CSS for disabled button (e.g. sharing on a direct post)
|
|
||||||
# - prevent double accept/double follow
|
# - prevent double accept/double follow
|
||||||
# - UI support for updating posts
|
# - UI support for updating posts
|
||||||
# - indieauth tweaks
|
# - indieauth tweaks
|
||||||
|
|
|
@ -503,7 +503,7 @@
|
||||||
</ul>
|
</ul>
|
||||||
</nav>
|
</nav>
|
||||||
|
|
||||||
{% if is_admin and (object.is_from_outbox or object.is_from_inbox) %}
|
{% if is_admin %}
|
||||||
<nav class="flexbox activity-bar">
|
<nav class="flexbox activity-bar">
|
||||||
<ul>
|
<ul>
|
||||||
{% if object.is_from_outbox %}
|
{% if object.is_from_outbox %}
|
||||||
|
@ -524,7 +524,7 @@
|
||||||
{{ admin_reply_button(object.ap_id) }}
|
{{ admin_reply_button(object.ap_id) }}
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
{% if object.is_from_inbox %}
|
{% if not object.is_from_outbox %}
|
||||||
<li>
|
<li>
|
||||||
{% if object.liked_via_outbox_object_ap_id %}
|
{% if object.liked_via_outbox_object_ap_id %}
|
||||||
{{ admin_undo_button(object.liked_via_outbox_object_ap_id, "unlike", object.permalink_id) }}
|
{{ admin_undo_button(object.liked_via_outbox_object_ap_id, "unlike", object.permalink_id) }}
|
||||||
|
@ -551,13 +551,17 @@
|
||||||
</li>
|
</li>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
|
{% if object.is_from_inbox %}
|
||||||
|
<li>
|
||||||
|
{{ admin_profile_button(object.actor.ap_id) }}
|
||||||
|
</li>
|
||||||
|
{% endif %}
|
||||||
|
{% endif %}
|
||||||
|
{% if object.is_from_inbox or object.is_from_outbox %}
|
||||||
<li>
|
<li>
|
||||||
{{ admin_profile_button(object.actor.ap_id) }}
|
{{ admin_expand_button(object.ap_id) }}
|
||||||
</li>
|
</li>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<li>
|
|
||||||
{{ admin_expand_button(object.ap_id) }}
|
|
||||||
</li>
|
|
||||||
</ul>
|
</ul>
|
||||||
</nav>
|
</nav>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
Loading…
Reference in New Issue