foxhole/app/boxes.py

105 lines
2.4 KiB
Python

#!/usr/bin/env python3
from typing import Any
import uuid
from app import models
from app.database import AsyncSession
from app.activitypub import ME
from app.config import MANUALLY_APPROVES_FOLLOWERS
from app.config import BASE_URL
from app.models import Actor
from app.actor import fetch_actor
import app.activitypub as ap
from sqlalchemy import select
from loguru import logger
from uuid import uuid4
def allocate_outbox_id() -> str:
return str(uuid.uuid4())
def build_object_id(id) -> str:
return f"{BASE_URL}/tail/{id}"
async def save_incoming(
db_session: AsyncSession,
payload: dict,
) -> models.IncomingActivity | None:
ap_id: str
if "@context" not in payload:
logger.warning(f"invalid object: {payload}")
return None
if "id" in payload:
ap_id = payload["id"]
else:
ap_id = str(uuid4())
incoming_activity = models.IncomingActivity(
ap_id=ap_id,
ap_object=payload,
)
await process_incoming(db_session, payload)
if db_session.add(incoming_activity):
return incoming_activity
await db_session.commit()
await db_session.refresh(incoming_activity)
return incoming_activity
async def process_incoming(
db_session: AsyncSession,
ap_object: dict,
) -> bool:
actor = await fetch_actor(ap_object["actor"], db_session)
if "Follow" == ap_object["type"]:
if await _handle_follow(db_session, actor.ap_actor["inbox"], ap_object):
return True
return False
return False
async def _handle_follow(
db_session : AsyncSession,
inbox_url : str | Any,
ap_object : dict,
) -> bool:
if ME["id"] != ap_object["object"]:
# await db_session.delete(ap_object)
logger.warning("no match follow object!" + ap_object["id"])
return False
if MANUALLY_APPROVES_FOLLOWERS:
# TODO
return False
await _send_accept(db_session, inbox_url, ap_object)
return True
async def _send_accept(
db_session: AsyncSession,
inbox_url : str | Any,
ap_object : dict,
) -> None :
reply_id = allocate_outbox_id()
url = inbox_url
out = {
"@context": ap.AS_CTX,
"id": build_object_id(reply_id),
"type": "Accept",
"actor": ME["id"],
"object": ap_object["id"],
}
#TODO outcoming
await ap.post(url, out)