From 8d8c69343ce06c459e03e0570dd15dd53d0bd4d3 Mon Sep 17 00:00:00 2001 From: Your Name Date: Wed, 15 Dec 2021 00:16:48 -0500 Subject: [PATCH] fix detail page 502 step 2: calculate relationship by local cached data --- common/models.py | 68 ++++++++++++------------------------------------ mastodon/api.py | 13 +++------ users/models.py | 31 ++++++++++++++++++---- 3 files changed, 46 insertions(+), 66 deletions(-) diff --git a/common/models.py b/common/models.py index f595be28..643c3394 100644 --- a/common/models.py +++ b/common/models.py @@ -159,63 +159,27 @@ class UserOwnedEntity(models.Model): class Meta: abstract = True + def is_visible_to(self, viewer): + owner = self.owner + if owner == viewer: + return True + if viewer.is_blocking(owner) or owner.is_blocking(viewer) or viewer.is_muting(owner): + return False + if self.is_private: + return viewer.is_following(owner) + else: + return True + @classmethod def get_available(cls, entity, request_user, token): - # TODO add amount limit for once query - """ - Returns all avaliable user-owned entities related to given entity. - This method handles mute/block relationships and private/public visibilities. - """ - # the foreign key field that points to entity - # has to be named as the lower case name of that entity + # e.g. SongMark.get_available(song, request.user, request.session['oauth_token']) query_kwargs = {entity.__class__.__name__.lower(): entity} - user_owned_entities = cls.objects.filter( - **query_kwargs).order_by("-edited_time") - - # every user should only be abled to have one user owned entity for each entity - # this is guaranteed by models - id_list = [] - - # none_index tracks those failed cross site id query - none_index = [] - - for (i, entity) in enumerate(user_owned_entities): - if entity.owner.mastodon_site == request_user.mastodon_site: - id_list.append(entity.owner.mastodon_id) - else: - # TODO there could be many requests therefore make the pulling asynchronized - cross_site_id = get_cross_site_id( - entity.owner, request_user.mastodon_site, token) - if not cross_site_id is None: - id_list.append(cross_site_id) - else: - none_index.append(i) - # populate those query-failed None postions - # to ensure the consistency of the orders of - # the three(id_list, user_owned_entities, relationships) - id_list.append(request_user.mastodon_id) - - # Mastodon request - relationships = get_relationships( - request_user.mastodon_site, id_list, token) - mute_block_blocked_index = [] - following_index = [] - for i, r in enumerate(relationships): - # the order of relationships is corresponding to the id_list, - # and the order of id_list is the same as user_owned_entiies - if r['blocking'] or r['blocked_by'] or r['muting']: - mute_block_blocked_index.append(i) - if r['following']: - following_index.append(i) - available_entities = [ - e for i, e in enumerate(user_owned_entities) - if ((e.is_private == True and i in following_index) or e.is_private == False or e.owner == request_user) - and not i in mute_block_blocked_index and not i in none_index - ] - return available_entities + all_entities = cls.objects.filter(**query_kwargs).order_by("-edited_time") # get all marks for song + visible_entities = list(filter(lambda _entity: _entity.is_visible_to(request_user), all_entities)) + return visible_entities @classmethod - def get_available_by_user(cls, owner, is_following): + def get_available_by_user(cls, owner, is_following): # FIXME """ Returns all avaliable owner's entities. Mute/Block relation is not handled in this method. diff --git a/mastodon/api.py b/mastodon/api.py index 079713c3..bc9498ca 100644 --- a/mastodon/api.py +++ b/mastodon/api.py @@ -136,15 +136,10 @@ def get_site_id(username, user_site, target_site, token): # high level api below def get_relationship(request_user, target_user, token): - if request_user.mastodon_site == target_user.mastodon_site: - return get_relationships(request_user.mastodon_site, target_user.mastodon_id, token) - else: - cross_site_id = get_cross_site_id(target_user, request_user.mastodon_site, token) - if cross_site_id is None: - return [{'blocked_by': True}] # boldly assume blocked(?!) if no relationship found - # FIXME should check the reverse direction? but need either cache the target user's oauth token or her blocked list - else: - return get_relationships(request_user.mastodon_site, cross_site_id, token) + return [{ + 'blocked_by': target_user.is_blocking(request_user), + 'following': request_user.is_following(target_user), + }] def get_cross_site_id(target_user, target_site, token): diff --git a/users/models.py b/users/models.py index 18a12e8a..c7141049 100644 --- a/users/models.py +++ b/users/models.py @@ -31,6 +31,7 @@ class User(AbstractUser): mastodon_following = models.JSONField(default=list) mastodon_mutes = models.JSONField(default=list) mastodon_blocks = models.JSONField(default=list) + mastodon_domain_blocks = models.JSONField(default=list) mastodon_account = models.JSONField(default=dict) mastodon_last_refresh = models.DateTimeField(default=timezone.now) # store the latest read announcement id, @@ -43,13 +44,17 @@ class User(AbstractUser): fields=['username', 'mastodon_site'], name="unique_user_identity") ] - def save(self, *args, **kwargs): - """ Automatically populate password field with settings.DEFAULT_PASSWORD before saving.""" - self.set_password(settings.DEFAULT_PASSWORD) - return super().save(*args, **kwargs) + # def save(self, *args, **kwargs): + # """ Automatically populate password field with settings.DEFAULT_PASSWORD before saving.""" + # self.set_password(settings.DEFAULT_PASSWORD) + # return super().save(*args, **kwargs) + + @property + def mastodon_username(self): + return self.username + '@' + self.mastodon_site def __str__(self): - return self.username + '@' + self.mastodon_site + return self.mastodon_username def refresh_mastodon_data(self): """ Try refresh account data from mastodon server, return true if refreshed successfully, note it will not save to db """ @@ -65,11 +70,27 @@ class User(AbstractUser): self.mastodon_following = get_related_acct_list(self.mastodon_site, self.mastodon_token, f'/api/v1/accounts/{self.mastodon_id}/following') self.mastodon_mutes = get_related_acct_list(self.mastodon_site, self.mastodon_token, '/api/v1/mutes') self.mastodon_blocks = get_related_acct_list(self.mastodon_site, self.mastodon_token, '/api/v1/blocks') + self.mastodon_domain_blocks = get_related_acct_list(self.mastodon_site, self.mastodon_token, '/api/v1/domain_blocks') updated = True elif code == 401: self.mastodon_token = '' return updated + def is_blocking(self, target): + return target.mastodon_username in self.mastodon_blocks or target.mastodon_site in self.mastodon_domain_blocks + + def is_blocked_by(self, target): + return target.is_blocking(self) + + def is_muting(self, target): + return target.mastodon_username in self.mastodon_mutes + + def is_following(self, target): + return self.mastodon_username in target.mastodon_followers if target.mastodon_locked else self.mastodon_username in target.mastodon_followers or target.mastodon_username in self.mastodon_following + + def is_followed_by(self, target): + return target.is_following(self) + class Preference(models.Model): user = models.OneToOneField(User, models.CASCADE, primary_key=True)