lib.itmens/users/models/apidentity.py

291 lines
8.5 KiB
Python
Raw Normal View History

2023-07-20 21:59:49 -04:00
from functools import cached_property
from django.conf import settings
from django.db import models
2024-07-01 17:29:38 -04:00
from mastodon.models.mastodon import MastodonAccount
2023-07-20 21:59:49 -04:00
from takahe.utils import Takahe
2023-08-13 18:00:10 -04:00
from .preference import Preference
2023-07-20 21:59:49 -04:00
from .user import User
class APIdentity(models.Model):
"""
An identity/actor in ActivityPub service.
This model is used as 1:1 mapping to Takahe Identity Model
"""
2024-07-01 17:29:38 -04:00
user: User
2024-07-05 10:53:43 -04:00
user_id: int
2023-08-13 18:00:10 -04:00
user = models.OneToOneField(
2024-07-01 17:29:38 -04:00
User, models.SET_NULL, related_name="identity", null=True
) # type:ignore
2023-07-20 21:59:49 -04:00
local = models.BooleanField()
username = models.CharField(max_length=500, blank=True, null=True)
domain_name = models.CharField(max_length=500, blank=True, null=True)
deleted = models.DateTimeField(null=True, blank=True)
2023-12-29 02:11:36 -05:00
anonymous_viewable = models.BooleanField(null=False, default=True)
2023-07-20 21:59:49 -04:00
class Meta:
indexes = [
models.Index(fields=["local", "username"]),
models.Index(fields=["domain_name", "username"]),
]
2023-08-13 18:00:10 -04:00
def __str__(self):
return f"{self.pk}:{self.username}@{self.domain_name}"
2023-07-20 21:59:49 -04:00
@cached_property
def takahe_identity(self):
return Takahe.get_identity(self.pk)
@property
def is_active(self):
return (
2023-11-19 09:22:24 -05:00
self.user.is_active if self.user else self.takahe_identity.deleted is None
)
2023-07-20 21:59:49 -04:00
@property
def name(self):
return self.takahe_identity.name
@property
def discoverable(self):
return self.takahe_identity.discoverable
2023-08-13 18:00:10 -04:00
@property
def locked(self):
return self.takahe_identity.manually_approves_followers
2023-07-20 21:59:49 -04:00
@property
def actor_uri(self):
return self.takahe_identity.actor_uri
@property
def icon_uri(self):
return self.takahe_identity.icon_uri
2023-08-14 11:42:09 -04:00
@property
def profile_uri(self):
return self.takahe_identity.profile_uri
2023-08-15 15:46:11 -04:00
@cached_property
2023-07-20 21:59:49 -04:00
def display_name(self):
2023-08-13 18:00:10 -04:00
return self.takahe_identity.name or self.username
2023-08-15 15:46:11 -04:00
@cached_property
2023-08-13 18:00:10 -04:00
def summary(self):
return self.takahe_identity.summary or ""
2023-07-20 21:59:49 -04:00
@property
def avatar(self):
2023-08-17 18:54:00 -04:00
if self.local:
2023-08-22 17:13:52 +00:00
return (
self.takahe_identity.icon.url
if self.takahe_identity.icon
else self.takahe_identity.icon_uri or settings.SITE_INFO["user_icon"]
2023-08-22 17:13:52 +00:00
)
2023-08-17 18:54:00 -04:00
else:
return f"/proxy/identity_icon/{self.pk}/"
2023-07-20 21:59:49 -04:00
@property
def url(self):
2024-02-25 23:04:50 -05:00
return f"/users/{self.handle}/" if self.local else f"/users/@{self.handle}/"
2023-07-20 21:59:49 -04:00
@property
def preference(self):
2023-08-13 18:00:10 -04:00
return self.user.preference if self.user else Preference()
@property
def full_handle(self):
return f"{self.username}@{self.domain_name}"
2023-07-20 21:59:49 -04:00
@property
2024-02-25 23:04:50 -05:00
def handle(self):
2023-07-20 21:59:49 -04:00
if self.local:
return self.username
else:
2024-02-25 23:04:50 -05:00
return f"{self.username}@{self.domain_name}"
2023-07-20 21:59:49 -04:00
@property
def restricted(self):
2025-01-17 22:07:46 -05:00
return self.takahe_identity.restriction == 2
2023-07-20 21:59:49 -04:00
@property
def following(self):
return Takahe.get_following_ids(self.pk)
2023-08-13 23:11:12 -04:00
@property
def followers(self):
return Takahe.get_follower_ids(self.pk)
2023-07-20 21:59:49 -04:00
@property
def muting(self):
return Takahe.get_muting_ids(self.pk)
@property
def blocking(self):
return Takahe.get_blocking_ids(self.pk)
2023-08-13 23:11:12 -04:00
@property
def following_identities(self):
return APIdentity.objects.filter(pk__in=self.following)
@property
def follower_identities(self):
return APIdentity.objects.filter(pk__in=self.followers)
@property
def muting_identities(self):
return APIdentity.objects.filter(pk__in=self.muting)
@property
def blocking_identities(self):
return APIdentity.objects.filter(pk__in=self.blocking)
2023-08-22 17:13:52 +00:00
@property
def requested_follower_identities(self):
return APIdentity.objects.filter(pk__in=self.requested_followers)
2023-08-13 23:11:12 -04:00
@property
def follow_requesting_identities(self):
2023-11-08 22:11:43 -05:00
return APIdentity.objects.filter(pk__in=self.following_requests)
2023-08-13 23:11:12 -04:00
2023-07-20 21:59:49 -04:00
@property
def rejecting(self):
return Takahe.get_rejecting_ids(self.pk)
@property
def ignoring(self):
return self.muting + self.rejecting
def follow(self, target: "APIdentity", force_accept: bool = False):
Takahe.follow(self.pk, target.pk, force_accept)
2023-07-20 21:59:49 -04:00
def unfollow(self, target: "APIdentity"): # this also cancels follow request
Takahe.unfollow(self.pk, target.pk)
2023-08-13 23:11:12 -04:00
@property
2023-07-20 21:59:49 -04:00
def requested_followers(self):
2023-08-13 23:11:12 -04:00
return Takahe.get_requested_follower_ids(self.pk)
2023-07-20 21:59:49 -04:00
2023-08-13 23:11:12 -04:00
@property
2023-11-08 22:11:43 -05:00
def following_requests(self):
2023-08-13 23:11:12 -04:00
return Takahe.get_following_request_ids(self.pk)
2023-07-20 21:59:49 -04:00
def accept_follow_request(self, target: "APIdentity"):
2023-08-22 17:13:52 +00:00
Takahe.accept_follow_request(target.pk, self.pk)
2023-07-20 21:59:49 -04:00
def reject_follow_request(self, target: "APIdentity"):
2023-08-22 17:13:52 +00:00
Takahe.reject_follow_request(target.pk, self.pk)
2023-07-20 21:59:49 -04:00
def block(self, target: "APIdentity"):
Takahe.block(self.pk, target.pk)
def unblock(self, target: "APIdentity"):
Takahe.unblock(self.pk, target.pk)
def mute(self, target: "APIdentity"):
Takahe.mute(self.pk, target.pk)
def unmute(self, target: "APIdentity"):
Takahe.unmute(self.pk, target.pk)
def is_rejecting(self, target: "APIdentity"):
return self != target and (
target.is_blocked_by(self) or target.is_blocking(self)
)
def is_blocking(self, target: "APIdentity"):
return Takahe.get_is_blocking(self.pk, target.pk)
2023-07-20 21:59:49 -04:00
def is_blocked_by(self, target: "APIdentity"):
return Takahe.get_is_blocking(target.pk, self.pk)
2023-07-20 21:59:49 -04:00
def is_muting(self, target: "APIdentity"):
return Takahe.get_is_muting(self.pk, target.pk)
2023-07-20 21:59:49 -04:00
def is_following(self, target: "APIdentity"):
return Takahe.get_is_following(self.pk, target.pk)
def is_followed_by(self, target: "APIdentity"):
return Takahe.get_is_following(target.pk, self.pk)
2023-07-20 21:59:49 -04:00
2023-08-13 23:11:12 -04:00
def is_requesting(self, target: "APIdentity"):
return Takahe.get_is_follow_requesting(self.pk, target.pk)
2023-08-13 23:11:12 -04:00
2023-08-22 17:13:52 +00:00
def is_requested(self, target: "APIdentity"):
return Takahe.get_is_follow_requesting(target.pk, self.pk)
2023-07-20 21:59:49 -04:00
@classmethod
2024-02-25 23:04:50 -05:00
def get_remote(cls, username, domain):
i = cls.objects.filter(
username__iexact=username, domain_name__iexact=domain, deleted__isnull=True
).first()
if i:
return i
2024-04-07 13:02:52 -04:00
if domain != settings.SITE_DOMAIN:
2024-02-25 23:04:50 -05:00
identity = Takahe.get_identity_by_handler(username, domain)
if identity:
return Takahe.get_or_create_remote_apidentity(identity)
@classmethod
def get_by_handle(cls, handler: str, match_linked=False) -> "APIdentity":
2023-08-13 18:00:10 -04:00
"""
Handler format
'id' - local identity with username 'id'
2024-02-25 23:04:50 -05:00
'id@site'
match_linked = True - local identity with linked mastodon id == 'id@site' (for backward compatibility)
match_linked = False - remote activitypub identity 'id@site'
2023-08-13 18:00:10 -04:00
'@id' - local identity with username 'id'
'@id@site' - remote activitypub identity 'id@site'
"""
2023-07-20 21:59:49 -04:00
s = handler.split("@")
2024-04-06 00:13:50 -04:00
sl = len(s)
if sl == 1 or (sl == 2 and s[0] == ""):
2023-07-20 21:59:49 -04:00
return cls.objects.get(
2024-04-06 00:13:50 -04:00
username__iexact=s[0] if sl == 1 else s[1],
2023-08-13 18:00:10 -04:00
local=True,
2023-07-20 21:59:49 -04:00
deleted__isnull=True,
)
2024-04-06 00:13:50 -04:00
elif sl == 2:
2024-02-25 23:04:50 -05:00
if match_linked:
2024-07-01 17:29:38 -04:00
i = MastodonAccount.objects.get(
handle__iexact=handler,
).user.identity
if i.deleted:
raise cls.DoesNotExist(f"Identity deleted {handler}")
return i
2024-02-25 23:04:50 -05:00
else:
i = cls.get_remote(s[0], s[1])
if i:
return i
2024-07-01 17:29:38 -04:00
raise cls.DoesNotExist(f"Identity not found {handler}")
2024-04-06 00:13:50 -04:00
elif sl == 3 and s[0] == "":
2024-02-25 23:04:50 -05:00
i = cls.get_remote(s[1], s[2])
2023-08-13 18:00:10 -04:00
if i:
return i
2024-02-25 23:04:50 -05:00
raise cls.DoesNotExist(f"Identity not found {handler}")
2023-07-20 21:59:49 -04:00
else:
2024-07-01 17:29:38 -04:00
raise cls.DoesNotExist(f"Identity handle invalid {handler}")
2023-07-20 21:59:49 -04:00
@cached_property
def activity_manager(self):
from social.models import ActivityManager
return ActivityManager(self)
@cached_property
def shelf_manager(self):
from journal.models import ShelfManager
return ShelfManager(self)
@cached_property
def tag_manager(self):
from journal.models import TagManager
return TagManager(self)