forked from forks/microblog.pub
141 lines
3.7 KiB
Python
141 lines
3.7 KiB
Python
|
from uuid import uuid4
|
||
|
|
||
|
import factory # type: ignore
|
||
|
from Crypto.PublicKey import RSA
|
||
|
from sqlalchemy import orm
|
||
|
|
||
|
from app import activitypub as ap
|
||
|
from app import actor
|
||
|
from app import models
|
||
|
from app.actor import RemoteActor
|
||
|
from app.ap_object import RemoteObject
|
||
|
from app.database import engine
|
||
|
|
||
|
_Session = orm.scoped_session(orm.sessionmaker(bind=engine))
|
||
|
|
||
|
|
||
|
def generate_key() -> tuple[str, str]:
|
||
|
k = RSA.generate(1024)
|
||
|
return k.exportKey("PEM").decode(), k.publickey().exportKey("PEM").decode()
|
||
|
|
||
|
|
||
|
def build_follow_activity(
|
||
|
from_remote_actor: actor.RemoteActor,
|
||
|
for_remote_actor: actor.RemoteActor,
|
||
|
outbox_public_id: str | None = None,
|
||
|
) -> ap.RawObject:
|
||
|
return {
|
||
|
"@context": ap.AS_CTX,
|
||
|
"type": "Follow",
|
||
|
"id": from_remote_actor.ap_id + "/follow/" + (outbox_public_id or uuid4().hex),
|
||
|
"actor": from_remote_actor.ap_id,
|
||
|
"object": for_remote_actor.ap_id,
|
||
|
}
|
||
|
|
||
|
|
||
|
def build_accept_activity(
|
||
|
from_remote_actor: actor.RemoteActor,
|
||
|
for_remote_object: RemoteObject,
|
||
|
outbox_public_id: str | None = None,
|
||
|
) -> ap.RawObject:
|
||
|
return {
|
||
|
"@context": ap.AS_CTX,
|
||
|
"type": "Accept",
|
||
|
"id": from_remote_actor.ap_id + "/accept/" + (outbox_public_id or uuid4().hex),
|
||
|
"actor": from_remote_actor.ap_id,
|
||
|
"object": for_remote_object.ap_id,
|
||
|
}
|
||
|
|
||
|
|
||
|
class BaseModelMeta:
|
||
|
sqlalchemy_session = _Session
|
||
|
sqlalchemy_session_persistence = "commit"
|
||
|
|
||
|
|
||
|
class RemoteActorFactory(factory.Factory):
|
||
|
class Meta:
|
||
|
model = RemoteActor
|
||
|
exclude = (
|
||
|
"base_url",
|
||
|
"username",
|
||
|
"public_key",
|
||
|
)
|
||
|
|
||
|
class Params:
|
||
|
icon_url = None
|
||
|
summary = "I like unit tests"
|
||
|
|
||
|
ap_actor = factory.LazyAttribute(
|
||
|
lambda o: {
|
||
|
"@context": ap.AS_CTX,
|
||
|
"type": "Person",
|
||
|
"id": o.base_url,
|
||
|
"following": o.base_url + "/following",
|
||
|
"followers": o.base_url + "/followers",
|
||
|
# "featured": ID + "/featured",
|
||
|
"inbox": o.base_url + "/inbox",
|
||
|
"outbox": o.base_url + "/outbox",
|
||
|
"preferredUsername": o.username,
|
||
|
"name": o.username,
|
||
|
"summary": o.summary,
|
||
|
"endpoints": {},
|
||
|
"url": o.base_url,
|
||
|
"manuallyApprovesFollowers": False,
|
||
|
"attachment": [],
|
||
|
"icon": {},
|
||
|
"publicKey": {
|
||
|
"id": f"{o.base_url}#main-key",
|
||
|
"owner": o.base_url,
|
||
|
"publicKeyPem": o.public_key,
|
||
|
},
|
||
|
}
|
||
|
)
|
||
|
|
||
|
|
||
|
class ActorFactory(factory.alchemy.SQLAlchemyModelFactory):
|
||
|
class Meta(BaseModelMeta):
|
||
|
model = models.Actor
|
||
|
|
||
|
# ap_actor
|
||
|
# ap_id
|
||
|
ap_type = "Person"
|
||
|
|
||
|
@classmethod
|
||
|
def from_remote_actor(cls, ra):
|
||
|
return cls(
|
||
|
ap_type=ra.ap_type,
|
||
|
ap_actor=ra.ap_actor,
|
||
|
ap_id=ra.ap_id,
|
||
|
)
|
||
|
|
||
|
|
||
|
class OutboxObjectFactory(factory.alchemy.SQLAlchemyModelFactory):
|
||
|
class Meta(BaseModelMeta):
|
||
|
model = models.OutboxObject
|
||
|
|
||
|
# public_id
|
||
|
# relates_to_inbox_object_id
|
||
|
# relates_to_outbox_object_id
|
||
|
|
||
|
@classmethod
|
||
|
def from_remote_object(cls, public_id, ro):
|
||
|
return cls(
|
||
|
public_id=public_id,
|
||
|
ap_type=ro.ap_type,
|
||
|
ap_id=ro.ap_id,
|
||
|
ap_context=ro.context,
|
||
|
ap_object=ro.ap_object,
|
||
|
visibility=ro.visibility,
|
||
|
og_meta=ro.og_meta,
|
||
|
activity_object_ap_id=ro.activity_object_ap_id,
|
||
|
is_hidden_from_homepage=True if ro.in_reply_to else False,
|
||
|
)
|
||
|
|
||
|
|
||
|
class OutgoingActivityFactory(factory.alchemy.SQLAlchemyModelFactory):
|
||
|
class Meta(BaseModelMeta):
|
||
|
model = models.OutgoingActivity
|
||
|
|
||
|
# recipient
|
||
|
# outbox_object_id
|