fix detail page 502 step 2: calculate relationship by local cached data

This commit is contained in:
Your Name 2021-12-15 00:16:48 -05:00
parent 879c21ca05
commit 8d8c69343c
3 changed files with 46 additions and 66 deletions

View file

@ -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.

View file

@ -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):

View file

@ -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)