bookwyrm/bookwyrm/activitypub/verbs.py

261 lines
7.1 KiB
Python
Raw Normal View History

""" activities that do things """
from dataclasses import dataclass, field
from typing import List
2021-02-17 00:35:28 +00:00
from django.apps import apps
2021-02-16 19:04:13 +00:00
from .base_activity import ActivityObject, Signature, resolve_remote_id
2021-04-08 21:16:34 +00:00
from .ordered_collection import CollectionItem
2021-02-16 05:41:08 +00:00
@dataclass(init=False)
class Verb(ActivityObject):
2021-04-26 16:15:42 +00:00
"""generic fields for activities"""
2021-03-08 16:49:10 +00:00
actor: str
object: ActivityObject
def action(self, allow_external_connections=True):
2021-04-26 16:15:42 +00:00
"""usually we just want to update and save"""
# self.object may return None if the object is invalid in an expected way
# ie, Question type
if self.object:
self.object.to_model(allow_external_connections=allow_external_connections)
2021-02-16 04:49:23 +00:00
2021-06-18 21:12:56 +00:00
# pylint: disable=invalid-name
@dataclass(init=False)
class Create(Verb):
2021-04-26 16:15:42 +00:00
"""Create activity"""
2021-03-08 16:49:10 +00:00
to: List[str]
cc: List[str] = field(default_factory=lambda: [])
2021-02-02 17:37:46 +00:00
signature: Signature = None
2021-03-08 16:49:10 +00:00
type: str = "Create"
2021-06-18 21:12:56 +00:00
# pylint: disable=invalid-name
2020-10-14 15:38:51 +00:00
@dataclass(init=False)
class Delete(Verb):
2021-04-26 16:15:42 +00:00
"""Create activity"""
2021-03-08 16:49:10 +00:00
2022-01-30 18:42:29 +00:00
to: List[str] = field(default_factory=lambda: [])
cc: List[str] = field(default_factory=lambda: [])
2021-03-08 16:49:10 +00:00
type: str = "Delete"
2020-10-14 15:38:51 +00:00
def action(self, allow_external_connections=True):
2021-04-26 16:15:42 +00:00
"""find and delete the activity object"""
if not self.object:
return
if isinstance(self.object, str):
# Deleted users are passed as strings. Not wild about this fix
model = apps.get_model("bookwyrm.User")
obj = model.find_existing_by_remote_id(self.object)
else:
obj = self.object.to_model(
save=False,
allow_create=False,
allow_external_connections=allow_external_connections,
)
if obj:
obj.delete()
# if we can't find it, we don't need to delete it because we don't have it
2021-02-16 04:49:23 +00:00
2021-06-18 21:12:56 +00:00
# pylint: disable=invalid-name
@dataclass(init=False)
class Update(Verb):
2021-04-26 16:15:42 +00:00
"""Update activity"""
2021-03-08 16:49:10 +00:00
to: List[str]
2021-03-08 16:49:10 +00:00
type: str = "Update"
def action(self, allow_external_connections=True):
2021-04-26 16:15:42 +00:00
"""update a model instance from the dataclass"""
2021-10-15 15:51:59 +00:00
if not self.object:
return
self.object.to_model(
allow_create=False, allow_external_connections=allow_external_connections
)
2021-02-16 04:49:23 +00:00
@dataclass(init=False)
class Undo(Verb):
2021-04-26 16:15:42 +00:00
"""Undo an activity"""
2021-03-08 16:49:10 +00:00
type: str = "Undo"
def action(self, allow_external_connections=True):
2021-04-26 16:15:42 +00:00
"""find and remove the activity object"""
if isinstance(self.object, str):
2023-01-10 22:24:02 +00:00
# it may be that something should be done with these, but idk what
# this seems just to be coming from pleroma
return
2021-02-17 00:35:28 +00:00
# this is so hacky but it does make it work....
# (because you Reject a request and Undo a follow
model = None
2021-03-08 16:49:10 +00:00
if self.object.type == "Follow":
model = apps.get_model("bookwyrm.UserFollows")
obj = self.object.to_model(
model=model,
save=False,
allow_create=False,
allow_external_connections=allow_external_connections,
)
if not obj:
2023-01-10 22:24:02 +00:00
# this could be a follow request not a follow proper
model = apps.get_model("bookwyrm.UserFollowRequest")
obj = self.object.to_model(
model=model,
save=False,
allow_create=False,
allow_external_connections=allow_external_connections,
)
else:
obj = self.object.to_model(
model=model,
save=False,
allow_create=False,
allow_external_connections=allow_external_connections,
)
if not obj:
# if we don't have the object, we can't undo it. happens a lot with boosts
return
2021-02-16 04:49:23 +00:00
obj.delete()
@dataclass(init=False)
class Follow(Verb):
2021-04-26 16:15:42 +00:00
"""Follow activity"""
2021-03-08 16:49:10 +00:00
2021-02-16 02:47:08 +00:00
object: str
2021-03-08 16:49:10 +00:00
type: str = "Follow"
def action(self, allow_external_connections=True):
2021-04-26 16:15:42 +00:00
"""relationship save"""
self.to_model(allow_external_connections=allow_external_connections)
2021-02-16 05:20:00 +00:00
2021-02-16 04:49:23 +00:00
2021-01-23 19:03:10 +00:00
@dataclass(init=False)
class Block(Verb):
2021-04-26 16:15:42 +00:00
"""Block activity"""
2021-03-08 16:49:10 +00:00
2021-02-16 02:47:08 +00:00
object: str
2021-03-08 16:49:10 +00:00
type: str = "Block"
def action(self, allow_external_connections=True):
2021-04-26 16:15:42 +00:00
"""relationship save"""
self.to_model(allow_external_connections=allow_external_connections)
2021-02-16 05:20:00 +00:00
2021-02-16 04:49:23 +00:00
@dataclass(init=False)
class Accept(Verb):
2021-04-26 16:15:42 +00:00
"""Accept activity"""
2021-03-08 16:49:10 +00:00
object: Follow
2021-03-08 16:49:10 +00:00
type: str = "Accept"
def action(self, allow_external_connections=True):
2022-01-30 18:42:29 +00:00
"""accept a request"""
obj = self.object.to_model(save=False, allow_create=True)
2021-02-16 04:49:23 +00:00
obj.accept()
@dataclass(init=False)
class Reject(Verb):
2021-04-26 16:15:42 +00:00
"""Reject activity"""
2021-03-08 16:49:10 +00:00
object: Follow
2021-03-08 16:49:10 +00:00
type: str = "Reject"
def action(self, allow_external_connections=True):
2022-01-30 18:42:29 +00:00
"""reject a follow request"""
2021-02-16 04:49:23 +00:00
obj = self.object.to_model(save=False, allow_create=False)
obj.reject()
@dataclass(init=False)
class Add(Verb):
2021-04-26 16:15:42 +00:00
"""Add activity"""
2021-03-08 16:49:10 +00:00
2021-04-08 21:16:34 +00:00
target: ActivityObject
object: CollectionItem
2021-03-08 16:49:10 +00:00
type: str = "Add"
def action(self, allow_external_connections=True):
2021-04-26 16:15:42 +00:00
"""figure out the target to assign the item to a collection"""
target = resolve_remote_id(self.target)
item = self.object.to_model(save=False)
setattr(item, item.collection_field, target)
item.save()
@dataclass(init=False)
2021-04-08 21:16:34 +00:00
class Remove(Add):
2021-04-26 16:15:42 +00:00
"""Remove activity"""
2021-03-08 16:49:10 +00:00
type: str = "Remove"
2021-02-16 04:49:23 +00:00
def action(self, allow_external_connections=True):
2021-04-26 16:15:42 +00:00
"""find and remove the activity object"""
obj = self.object.to_model(save=False, allow_create=False)
2021-04-22 16:25:12 +00:00
if obj:
obj.delete()
2021-02-16 05:20:00 +00:00
@dataclass(init=False)
class Like(Verb):
2021-04-26 16:15:42 +00:00
"""a user faving an object"""
2021-03-08 16:49:10 +00:00
2021-02-16 05:20:00 +00:00
object: str
2021-03-08 16:49:10 +00:00
type: str = "Like"
2021-02-16 05:20:00 +00:00
def action(self, allow_external_connections=True):
2021-04-26 16:15:42 +00:00
"""like"""
self.to_model(allow_external_connections=allow_external_connections)
2021-02-16 05:20:00 +00:00
2021-06-18 21:12:56 +00:00
# pylint: disable=invalid-name
2021-02-16 05:20:00 +00:00
@dataclass(init=False)
class Announce(Verb):
2021-04-26 16:15:42 +00:00
"""boosting a status"""
2021-03-08 16:49:10 +00:00
published: str
to: List[str] = field(default_factory=lambda: [])
cc: List[str] = field(default_factory=lambda: [])
2021-02-16 05:20:00 +00:00
object: str
2021-03-08 16:49:10 +00:00
type: str = "Announce"
2021-02-16 05:20:00 +00:00
def action(self, allow_external_connections=True):
2021-04-26 16:15:42 +00:00
"""boost"""
self.to_model(allow_external_connections=allow_external_connections)
2023-08-29 11:07:41 +00:00
2023-08-29 11:07:41 +00:00
@dataclass(init=False)
class Move(Verb):
"""a user moving an object"""
object: str
type: str = "Move"
origin: str = None
target: str = None
2023-08-29 11:07:41 +00:00
def action(self, allow_external_connections=True):
"""move"""
object_is_user = resolve_remote_id(remote_id=self.object, model="User")
2023-08-29 11:07:41 +00:00
if object_is_user:
model = apps.get_model("bookwyrm.MoveUser")
self.to_model(
model=model,
save=True,
allow_external_connections=allow_external_connections,
)
2023-08-29 11:07:41 +00:00
else:
2023-09-25 05:29:01 +00:00
# we might do something with this to move other objects at some point
pass