diff --git a/bookwyrm/models/federated_server.py b/bookwyrm/models/federated_server.py index e297c46c4..2be13b38b 100644 --- a/bookwyrm/models/federated_server.py +++ b/bookwyrm/models/federated_server.py @@ -28,7 +28,7 @@ class FederatedServer(BookWyrmModel): def block(self): """block a server""" self.status = "blocked" - self.save() + self.save(update_fields=["status"]) # deactivate all associated users self.user_set.filter(is_active=True).update( @@ -45,7 +45,7 @@ class FederatedServer(BookWyrmModel): def unblock(self): """unblock a server""" self.status = "federated" - self.save() + self.save(update_fields=["status"]) self.user_set.filter(deactivation_reason="domain_block").update( is_active=True, deactivation_reason=None diff --git a/bookwyrm/suggested_users.py b/bookwyrm/suggested_users.py index 92902938a..883430614 100644 --- a/bookwyrm/suggested_users.py +++ b/bookwyrm/suggested_users.py @@ -86,10 +86,12 @@ class SuggestedUsers(RedisStore): values = self.get_store(self.store_id(user), withscores=True) results = [] # annotate users with mutuals and shared book counts - for user_id, rank in values[:5]: + for user_id, rank in values: counts = self.get_counts_from_rank(rank) try: - user = models.User.objects.get(id=user_id) + user = models.User.objects.get( + id=user_id, is_active=True, bookwyrm_user=True + ) except models.User.DoesNotExist as err: # if this happens, the suggestions are janked way up logger.exception(err) @@ -97,6 +99,8 @@ class SuggestedUsers(RedisStore): user.mutuals = counts["mutuals"] # user.shared_books = counts["shared_books"] results.append(user) + if len(results) >= 5: + break return results @@ -178,13 +182,21 @@ def update_suggestions_on_unfollow(sender, instance, **kwargs): @receiver(signals.post_save, sender=models.User) # pylint: disable=unused-argument, too-many-arguments -def add_new_user(sender, instance, created, update_fields=None, **kwargs): - """a new user, wow how cool""" +def update_user(sender, instance, created, update_fields=None, **kwargs): + """an updated user, neat""" # a new user is found, create suggestions for them if created and instance.local: rerank_suggestions_task.delay(instance.id) - if update_fields and not "discoverable" in update_fields: + # we know what fields were updated and discoverability didn't change + if not instance.bookwyrm_user or ( + update_fields and not "discoverable" in update_fields + ): + return + + # deleted the user + if not created and not instance.is_active: + remove_user_task.delay(instance.id) return # this happens on every save, not just when discoverability changes, annoyingly @@ -194,6 +206,25 @@ def add_new_user(sender, instance, created, update_fields=None, **kwargs): remove_user_task.delay(instance.id) +@receiver(signals.post_save, sender=models.FederatedServer) +def domain_level_update(sender, instance, created, update_fields=None, **kwargs): + """remove users on a domain block""" + if ( + not update_fields + or "status" not in update_fields + or instance.application_type != "bookwyrm" + ): + return + + if instance.status == "blocked": + bulk_remove_instance_task.delay(instance.id) + return + bulk_add_instance_task.delay(instance.id) + + +# ------------------- TASKS + + @app.task(queue="low_priority") def rerank_suggestions_task(user_id): """do the hard work in celery""" @@ -219,3 +250,17 @@ def remove_suggestion_task(user_id, suggested_user_id): """remove a specific user from a specific user's suggestions""" suggested_user = models.User.objects.get(id=suggested_user_id) suggested_users.remove_suggestion(user_id, suggested_user) + + +@app.task(queue="low_priority") +def bulk_remove_instance_task(instance_id): + """remove a bunch of users from recs""" + for user in models.User.objects.filter(federated_server__id=instance_id): + suggested_users.remove_object_from_related_stores(user) + + +@app.task(queue="low_priority") +def bulk_add_instance_task(instance_id): + """remove a bunch of users from recs""" + for user in models.User.objects.filter(federated_server__id=instance_id): + suggested_users.rerank_obj(user, update_only=False) diff --git a/bookwyrm/tests/views/test_federation.py b/bookwyrm/tests/views/test_federation.py index ce5de7e33..493aaf93b 100644 --- a/bookwyrm/tests/views/test_federation.py +++ b/bookwyrm/tests/views/test_federation.py @@ -80,7 +80,9 @@ class FederationViews(TestCase): request.user = self.local_user request.user.is_superuser = True - view(request, server.id) + with patch("bookwyrm.suggested_users.bulk_remove_instance_task.delay") as mock: + view(request, server.id) + self.assertEqual(mock.call_count, 1) server.refresh_from_db() self.remote_user.refresh_from_db() @@ -118,7 +120,11 @@ class FederationViews(TestCase): request.user = self.local_user request.user.is_superuser = True - views.federation.unblock_server(request, server.id) + with patch("bookwyrm.suggested_users.bulk_add_instance_task.delay") as mock: + views.federation.unblock_server(request, server.id) + self.assertEqual(mock.call_count, 1) + self.assertEqual(mock.call_args[0][0], server.id) + server.refresh_from_db() self.remote_user.refresh_from_db() self.assertEqual(server.status, "federated")