diff --git a/mastodon/models/bluesky.py b/mastodon/models/bluesky.py
index 90c6fd28..8d7b4302 100644
--- a/mastodon/models/bluesky.py
+++ b/mastodon/models/bluesky.py
@@ -4,12 +4,14 @@ from functools import cached_property
from atproto import Client, SessionEvent, client_utils
from atproto_client import models
+from atproto_client.exceptions import AtProtocolError
from atproto_identity.did.resolver import DidResolver
from atproto_identity.handle.resolver import HandleResolver
from django.utils import timezone
from loguru import logger
from catalog.common import jsondata
+from takahe.utils import Takahe
from .common import SocialAccount
@@ -172,6 +174,52 @@ class BlueskyAccount(SocialAccount):
)
return True
+ def refresh_graph(self, save=True) -> bool:
+ try:
+ r = self._client.get_followers(self.uid)
+ self.followers = [p.did for p in r.followers]
+ r = self._client.get_follows(self.uid)
+ self.following = [p.did for p in r.follows]
+ r = self._client.app.bsky.graph.get_mutes(
+ models.AppBskyGraphGetMutes.Params(cursor=None, limit=None)
+ )
+ self.mutes = [p.did for p in r.mutes]
+ except AtProtocolError as e:
+ logger.warning(f"{self} refresh_graph error: {e}")
+ return False
+ if save:
+ self.save(
+ update_fields=[
+ "followers",
+ "following",
+ "mutes",
+ ]
+ )
+ return True
+
+ def sync_graph(self):
+ c = 0
+
+ def get_identity_ids(accts: list):
+ return set(
+ BlueskyAccount.objects.filter(
+ domain=Bluesky._DOMAIN, uid__in=accts
+ ).values_list("user__identity", flat=True)
+ )
+
+ me = self.user.identity.pk
+ for target_identity in get_identity_ids(self.following):
+ if not Takahe.get_is_following(me, target_identity):
+ Takahe.follow(me, target_identity, True)
+ c += 1
+
+ for target_identity in get_identity_ids(self.mutes):
+ if not Takahe.get_is_muting(me, target_identity):
+ Takahe.mute(me, target_identity)
+ c += 1
+
+ return c
+
def post(
self,
content,
diff --git a/mastodon/models/common.py b/mastodon/models/common.py
index f87600a8..a946b684 100644
--- a/mastodon/models/common.py
+++ b/mastodon/models/common.py
@@ -44,13 +44,13 @@ class SocialAccount(TypedModel):
last_refresh = models.DateTimeField(default=None, null=True)
last_reachable = models.DateTimeField(default=None, null=True)
- sync_profile = jsondata.BooleanField(
- json_field_name="preference_data", default=True
- )
- sync_graph = jsondata.BooleanField(json_field_name="preference_data", default=True)
- sync_timeline = jsondata.BooleanField(
- json_field_name="preference_data", default=True
- )
+ # sync_profile = jsondata.BooleanField(
+ # json_field_name="preference_data", default=True
+ # )
+ # sync_graph = jsondata.BooleanField(json_field_name="preference_data", default=True)
+ # sync_timeline = jsondata.BooleanField(
+ # json_field_name="preference_data", default=True
+ # )
class Meta:
indexes = [
@@ -124,3 +124,6 @@ class SocialAccount(TypedModel):
self.refresh_graph()
logger.debug(f"{self} refreshed")
return True
+
+ def sync_graph(self) -> int:
+ return 0
diff --git a/mastodon/models/mastodon.py b/mastodon/models/mastodon.py
index d465e380..191f50ba 100644
--- a/mastodon/models/mastodon.py
+++ b/mastodon/models/mastodon.py
@@ -778,6 +778,46 @@ class MastodonAccount(SocialAccount):
)
return True
+ def sync_graph(self):
+ c = 0
+
+ def get_identity_ids(accts: list):
+ return set(
+ MastodonAccount.objects.filter(handle__in=accts).values_list(
+ "user__identity", flat=True
+ )
+ )
+
+ def get_identity_ids_in_domains(domains: list):
+ return set(
+ MastodonAccount.objects.filter(domain__in=domains).values_list(
+ "user__identity", flat=True
+ )
+ )
+
+ me = self.user.identity.pk
+ for target_identity in get_identity_ids(self.following):
+ if not Takahe.get_is_following(me, target_identity):
+ Takahe.follow(me, target_identity, True)
+ c += 1
+
+ for target_identity in get_identity_ids(self.blocks):
+ if not Takahe.get_is_blocking(me, target_identity):
+ Takahe.block(me, target_identity)
+ c += 1
+
+ for target_identity in get_identity_ids_in_domains(self.domain_blocks):
+ if not Takahe.get_is_blocking(me, target_identity):
+ Takahe.block(me, target_identity)
+ c += 1
+
+ for target_identity in get_identity_ids(self.mutes):
+ if not Takahe.get_is_muting(me, target_identity):
+ Takahe.mute(me, target_identity)
+ c += 1
+
+ return c
+
def boost(self, post_url: str):
boost_toot(self._api_domain, self.access_token, post_url)
diff --git a/users/models/user.py b/users/models/user.py
index 101f69a7..81b75378 100644
--- a/users/models/user.py
+++ b/users/models/user.py
@@ -254,40 +254,6 @@ class User(AbstractUser):
self.identity.save()
self.social_accounts.all().delete()
- def sync_relationship(self):
- def get_identity_ids(accts: list):
- return set(
- MastodonAccount.objects.filter(handle__in=accts).values_list(
- "user__identity", flat=True
- )
- )
-
- def get_identity_ids_in_domains(domains: list):
- return set(
- MastodonAccount.objects.filter(domain__in=domains).values_list(
- "user__identity", flat=True
- )
- )
-
- me = self.identity.pk
- if not self.mastodon:
- return
- for target_identity in get_identity_ids(self.mastodon.following):
- if not Takahe.get_is_following(me, target_identity):
- Takahe.follow(me, target_identity, True)
-
- for target_identity in get_identity_ids(self.mastodon.blocks):
- if not Takahe.get_is_blocking(me, target_identity):
- Takahe.block(me, target_identity)
-
- for target_identity in get_identity_ids_in_domains(self.mastodon.domain_blocks):
- if not Takahe.get_is_blocking(me, target_identity):
- Takahe.block(me, target_identity)
-
- for target_identity in get_identity_ids(self.mastodon.mutes):
- if not Takahe.get_is_muting(me, target_identity):
- Takahe.mute(me, target_identity)
-
def sync_identity(self):
"""sync display name, bio, and avatar from available sources"""
identity = self.identity.takahe_identity
@@ -356,17 +322,18 @@ class User(AbstractUser):
if skip_graph:
return
if not self.preference.mastodon_skip_relationship:
- self.sync_relationship()
- return
+ c = 0
+ for account in self.social_accounts.all():
+ c += account.sync_graph()
+ if c:
+ logger.debug(f"{self} graph updated with {c} new relationship.")
@staticmethod
def sync_accounts_task(user_id):
user = User.objects.get(pk=user_id)
logger.info(f"{user} accounts sync start")
- if user.sync_accounts():
- logger.info(f"{user} accounts sync done")
- else:
- logger.warning(f"{user} accounts sync failed")
+ user.sync_accounts()
+ logger.info(f"{user} accounts sync end")
def sync_accounts_later(self):
django_rq.get_queue("mastodon").enqueue(User.sync_accounts_task, self.pk)
diff --git a/users/templates/users/account.html b/users/templates/users/account.html
index 7f43bfca..e747de6f 100644
--- a/users/templates/users/account.html
+++ b/users/templates/users/account.html
@@ -129,143 +129,144 @@
{% endif %}
+ {% if enable_threads %}
+
+
+ {% trans "Threads.net" %}
+
+ {% if request.user.threads %}
+
+ {% endif %}
+
+
+ {% endif %}
+ {% if enable_bluesky %}
+
+
+ {% trans "Bluesky (ATProto)" %}
+
+ {% if request.user.bluesky %}
+
+ {% endif %}
+
+
+ {% endif %}
+ {% endif %}
+ {% if request.user.social_accounts.all %}
- {% trans "Threads.net" %}
-
- {% if request.user.threads %}
-
- {% endif %}
-
-
-
-
- {% trans "Bluesky (ATProto)" %}
-
+
- {% if request.user.bluesky %}
-
- {% endif %}
{% endif %}
-
-
- {% trans 'Sync and import social account' %}
-
-
-
-
{% trans 'Users you are following' %}
diff --git a/users/views/profile.py b/users/views/profile.py
index 7a5a9bcc..cf02efeb 100644
--- a/users/views/profile.py
+++ b/users/views/profile.py
@@ -37,6 +37,9 @@ def account_info(request):
"users/account.html",
{
"allow_any_site": settings.MASTODON_ALLOW_ANY_SITE,
+ "enable_email": settings.ENABLE_LOGIN_EMAIL,
+ "enable_threads": settings.ENABLE_LOGIN_THREADS,
+ "enable_bluesky": settings.ENABLE_LOGIN_BLUESKY,
"profile_form": profile_form,
},
)