diff --git a/bookwyrm/management/commands/remove_remote_user_preview_images.py b/bookwyrm/management/commands/remove_remote_user_preview_images.py new file mode 100644 index 000000000..d4dc131d8 --- /dev/null +++ b/bookwyrm/management/commands/remove_remote_user_preview_images.py @@ -0,0 +1,40 @@ +""" Remove preview images for remote users """ +from django.core.management.base import BaseCommand +from django.db.models import Q + +from bookwyrm import models, preview_images + + +# pylint: disable=line-too-long +class Command(BaseCommand): + """Remove preview images for remote users""" + + help = "Remove preview images for remote users" + + # pylint: disable=no-self-use,unused-argument + def handle(self, *args, **options): + """generate preview images""" + self.stdout.write( + " | Hello! I will be removing preview images from remote users." + ) + self.stdout.write( + "πŸ§‘β€πŸš’ ⎨ This might take quite long if your instance has a lot of remote users." + ) + self.stdout.write(" | ✧ Thank you for your patience ✧") + + users = models.User.objects.filter(local=False).exclude( + Q(preview_image="") | Q(preview_image=None) + ) + + if len(users) > 0: + self.stdout.write( + f" β†’ Remote user preview images ({len(users)}): ", ending="" + ) + for user in users: + preview_images.remove_user_preview_image_task.delay(user.id) + self.stdout.write(".", ending="") + self.stdout.write(" OK πŸ–Ό") + else: + self.stdout.write(f" | There was no remote users with preview images.") + + self.stdout.write("πŸ§‘β€πŸš’ ⎨ I’m all done! ✧ Enjoy ✧") diff --git a/bookwyrm/models/user.py b/bookwyrm/models/user.py index 7df9da88d..f2a546737 100644 --- a/bookwyrm/models/user.py +++ b/bookwyrm/models/user.py @@ -526,6 +526,11 @@ def preview_image(instance, *args, **kwargs): """create preview images when user is updated""" if not ENABLE_PREVIEW_IMAGES: return + + # don't call the task for remote users + if not instance.local: + return + changed_fields = instance.field_tracker.changed() if len(changed_fields) > 0: diff --git a/bookwyrm/preview_images.py b/bookwyrm/preview_images.py index 99e2d8177..549e12472 100644 --- a/bookwyrm/preview_images.py +++ b/bookwyrm/preview_images.py @@ -472,12 +472,15 @@ def generate_edition_preview_image_task(book_id): @app.task(queue=LOW) def generate_user_preview_image_task(user_id): - """generate preview_image for a book""" + """generate preview_image for a user""" if not settings.ENABLE_PREVIEW_IMAGES: return user = models.User.objects.get(id=user_id) + if not user.local: + return + texts = { "text_one": user.display_name, "text_three": f"@{user.localname}@{settings.DOMAIN}", @@ -491,3 +494,25 @@ def generate_user_preview_image_task(user_id): image = generate_preview_image(texts=texts, picture=avatar) save_and_cleanup(image, instance=user) + + +@app.task(queue=LOW) +def remove_user_preview_image_task(user_id): + """remove preview_image for a user""" + if not settings.ENABLE_PREVIEW_IMAGES: + return + + user = models.User.objects.get(id=user_id) + + try: + file_name = user.preview_image.name + except ValueError: + file_name = None + + # Delete image in model + user.preview_image.delete(save=False) + user.save(broadcast=False, update_fields=["preview_image"]) + + # Delete image file + if file_name and default_storage.exists(file_name): + default_storage.delete(file_name) diff --git a/bookwyrm/tests/test_preview_images.py b/bookwyrm/tests/test_preview_images.py index 79ee195d7..d1998bf3c 100644 --- a/bookwyrm/tests/test_preview_images.py +++ b/bookwyrm/tests/test_preview_images.py @@ -14,6 +14,7 @@ from bookwyrm.preview_images import ( generate_edition_preview_image_task, generate_user_preview_image_task, generate_preview_image, + remove_user_preview_image_task, save_and_cleanup, ) @@ -46,6 +47,37 @@ class PreviewImages(TestCase): ), ) + with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( + "bookwyrm.activitystreams.populate_stream_task.delay" + ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): + self.remote_user = models.User.objects.create_user( + "rat", + "rat@rat.com", + "ratword", + local=False, + remote_id="https://example.com/users/rat", + inbox="https://example.com/users/rat/inbox", + outbox="https://example.com/users/rat/outbox", + ) + + with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( + "bookwyrm.activitystreams.populate_stream_task.delay" + ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): + self.remote_user_with_preview = models.User.objects.create_user( + "badger@your.domain.here", + "badger@badger.com", + "badgeword", + local=False, + remote_id="https://example.com/users/badger", + inbox="https://example.com/users/badger/inbox", + outbox="https://example.com/users/badger/outbox", + avatar=SimpleUploadedFile( + avatar_file, + open(avatar_file, "rb").read(), + content_type="image/jpeg", + ), + ) + self.work = models.Work.objects.create(title="Test Work") self.edition = models.Edition.objects.create( title="Example Edition", @@ -122,6 +154,14 @@ class PreviewImages(TestCase): self.local_user.preview_image.height, settings.PREVIEW_IMG_HEIGHT ) + def test_remote_user_preview(self, *args, **kwargs): + """a remote user doesn’t get a user preview""" + generate_user_preview_image_task(self.remote_user.id) + + self.remote_user.refresh_from_db() + + self.assertFalse(self.remote_user.preview_image) + def test_generate_user_preview_images_task(self, *args, **kwargs): """test task's external calls""" with patch("bookwyrm.preview_images.generate_preview_image") as generate_mock: @@ -129,3 +169,11 @@ class PreviewImages(TestCase): args = generate_mock.call_args.kwargs self.assertEqual(args["texts"]["text_one"], "possum") self.assertEqual(args["texts"]["text_three"], f"@possum@{settings.DOMAIN}") + + def test_remove_user_preview_image_task(self, *args, **kwargs): + """you can delete the preview image for a (remote) user""" + remove_user_preview_image_task(self.remote_user_with_preview.id) + + self.remote_user_with_preview.refresh_from_db() + + self.assertFalse(self.remote_user_with_preview.preview_image) diff --git a/bw-dev b/bw-dev index 7ce1755a1..446b3e425 100755 --- a/bw-dev +++ b/bw-dev @@ -228,6 +228,9 @@ case "$CMD" in generate_preview_images) runweb python manage.py generate_preview_images "$@" ;; + remove_remote_user_preview_images) + runweb python manage.py remove_remote_user_preview_images + ;; copy_media_to_s3) awscommand "bookwyrm_media_volume:/images"\ "s3 cp /images s3://${AWS_STORAGE_BUCKET_NAME}/images\ @@ -307,6 +310,7 @@ case "$CMD" in echo " populate_suggestions" echo " generate_thumbnails" echo " generate_preview_images [--all]" + echo " remove_remote_user_preview_images" echo " copy_media_to_s3" echo " sync_media_to_s3" echo " set_cors_to_s3 [cors file]" diff --git a/complete_bwdev.fish b/complete_bwdev.fish index 6f4172972..61a8fb3b2 100644 --- a/complete_bwdev.fish +++ b/complete_bwdev.fish @@ -32,6 +32,7 @@ populate_lists_streams \ populate_suggestions \ generate_thumbnails \ generate_preview_images \ +remove_remote_user_preview_images \ copy_media_to_s3 \ set_cors_to_s3 \ setup \ @@ -44,43 +45,44 @@ function __bw_complete -a cmds cmd desc complete -f -c bw-dev -n "not __fish_seen_subcommand_from $cmds" -a $cmd -d $desc end -__bw_complete "$commands" "up" "bring one or all service(s) up" -__bw_complete "$commands" "service_ports_web" "run command on the web container with its portsenabled and mapped" -__bw_complete "$commands" "initdb" "initialize database" -__bw_complete "$commands" "resetdb" "!! WARNING !! reset database" -__bw_complete "$commands" "makemigrations" "create new migrations" -__bw_complete "$commands" "migrate" "perform all migrations" -__bw_complete "$commands" "bash" "open up bash within the web container" -__bw_complete "$commands" "shell" "open the Python shell within the web container" -__bw_complete "$commands" "dbshell" "open the database shell within the web container" -__bw_complete "$commands" "restart_celery" "restart the celery container" -__bw_complete "$commands" "pytest" "run unit tests" -__bw_complete "$commands" "compile_themes" "compile themes css files" -__bw_complete "$commands" "collectstatic" "copy changed static files into the installation" -__bw_complete "$commands" "makemessages" "extract all localizable messages from the code" -__bw_complete "$commands" "compilemessages" "compile .po localization files to .mo" -__bw_complete "$commands" "update_locales" "run makemessages and compilemessages for the en_US and additional locales" -__bw_complete "$commands" "build" "build the containers" -__bw_complete "$commands" "clean" "bring the cluster down and remove all containers" -__bw_complete "$commands" "black" "run Python code formatting tool" -__bw_complete "$commands" "prettier" "run JavaScript code formatting tool" -__bw_complete "$commands" "eslint" "run JavaScript linting tool" -__bw_complete "$commands" "stylelint" "run SCSS linting tool" -__bw_complete "$commands" "formatters" "run multiple formatter tools" -__bw_complete "$commands" "populate_streams" "populate the main streams" -__bw_complete "$commands" "populate_lists_streams" "populate streams for book lists" -__bw_complete "$commands" "populate_suggestions" "populate book suggestions" -__bw_complete "$commands" "generate_thumbnails" "generate book thumbnails" -__bw_complete "$commands" "generate_preview_images" "generate book preview images" -__bw_complete "$commands" "collectstatic_watch" "watch filesystem and copy changed static files" -__bw_complete "$commands" "copy_media_to_s3" "run the `s3 cp` command to copy media to a bucket on S3" -__bw_complete "$commands" "sync_media_to_s3" "run the `s3 sync` command to sync media with a bucket on S3" -__bw_complete "$commands" "set_cors_to_s3" "push a CORS configuration defined in .json to s3" -__bw_complete "$commands" "setup" "perform first-time setup" -__bw_complete "$commands" "admin_code" "get the admin code" -__bw_complete "$commands" "remove_2fa" "remove 2FA from user" -__bw_complete "$commands" "confirm_email" "manually confirm email of user and set active" -__bw_complete "$commands" "runweb" "run a command on the web container" +__bw_complete "$commands" "up" "bring one or all service(s) up" +__bw_complete "$commands" "service_ports_web" "run command on the web container with its portsenabled and mapped" +__bw_complete "$commands" "initdb" "initialize database" +__bw_complete "$commands" "resetdb" "!! WARNING !! reset database" +__bw_complete "$commands" "makemigrations" "create new migrations" +__bw_complete "$commands" "migrate" "perform all migrations" +__bw_complete "$commands" "bash" "open up bash within the web container" +__bw_complete "$commands" "shell" "open the Python shell within the web container" +__bw_complete "$commands" "dbshell" "open the database shell within the web container" +__bw_complete "$commands" "restart_celery" "restart the celery container" +__bw_complete "$commands" "pytest" "run unit tests" +__bw_complete "$commands" "compile_themes" "compile themes css files" +__bw_complete "$commands" "collectstatic" "copy changed static files into the installation" +__bw_complete "$commands" "makemessages" "extract all localizable messages from the code" +__bw_complete "$commands" "compilemessages" "compile .po localization files to .mo" +__bw_complete "$commands" "update_locales" "run makemessages and compilemessages for the en_US and additional locales" +__bw_complete "$commands" "build" "build the containers" +__bw_complete "$commands" "clean" "bring the cluster down and remove all containers" +__bw_complete "$commands" "black" "run Python code formatting tool" +__bw_complete "$commands" "prettier" "run JavaScript code formatting tool" +__bw_complete "$commands" "eslint" "run JavaScript linting tool" +__bw_complete "$commands" "stylelint" "run SCSS linting tool" +__bw_complete "$commands" "formatters" "run multiple formatter tools" +__bw_complete "$commands" "populate_streams" "populate the main streams" +__bw_complete "$commands" "populate_lists_streams" "populate streams for book lists" +__bw_complete "$commands" "populate_suggestions" "populate book suggestions" +__bw_complete "$commands" "generate_thumbnails" "generate book thumbnails" +__bw_complete "$commands" "generate_preview_images" "generate site/book/user preview images" +__bw_complete "$commands" "remove_remote_user_preview_images" "remove preview images for remote users" +__bw_complete "$commands" "collectstatic_watch" "watch filesystem and copy changed static files" +__bw_complete "$commands" "copy_media_to_s3" "run the `s3 cp` command to copy media to a bucket on S3" +__bw_complete "$commands" "sync_media_to_s3" "run the `s3 sync` command to sync media with a bucket on S3" +__bw_complete "$commands" "set_cors_to_s3" "push a CORS configuration defined in .json to s3" +__bw_complete "$commands" "setup" "perform first-time setup" +__bw_complete "$commands" "admin_code" "get the admin code" +__bw_complete "$commands" "remove_2fa" "remove 2FA from user" +__bw_complete "$commands" "confirm_email" "manually confirm email of user and set active" +__bw_complete "$commands" "runweb" "run a command on the web container" function __bw_complete_subcommand -a cmd diff --git a/complete_bwdev.sh b/complete_bwdev.sh index 365b58369..749737564 100644 --- a/complete_bwdev.sh +++ b/complete_bwdev.sh @@ -29,6 +29,7 @@ populate_lists_streams populate_suggestions generate_thumbnails generate_preview_images +remove_remote_user_preview_images copy_media_to_s3 set_cors_to_s3 setup diff --git a/complete_bwdev.zsh b/complete_bwdev.zsh index 5df0c6533..26ff6a553 100644 --- a/complete_bwdev.zsh +++ b/complete_bwdev.zsh @@ -31,6 +31,7 @@ populate_lists_streams populate_suggestions generate_thumbnails generate_preview_images +remove_remote_user_preview_images copy_media_to_s3 set_cors_to_s3 setup