diff --git a/bookwyrm/activitypub/base_activity.py b/bookwyrm/activitypub/base_activity.py index 52b1b1f27..4f7b55d50 100644 --- a/bookwyrm/activitypub/base_activity.py +++ b/bookwyrm/activitypub/base_activity.py @@ -213,7 +213,7 @@ class ActivityObject: return data -@app.task +@app.task(queue="medium_priority") @transaction.atomic def set_related_field( model_name, origin_model_name, related_field_name, related_remote_id, data diff --git a/bookwyrm/activitystreams.py b/bookwyrm/activitystreams.py index f59eaf2e6..c32dfa35d 100644 --- a/bookwyrm/activitystreams.py +++ b/bookwyrm/activitystreams.py @@ -395,7 +395,7 @@ def remove_statuses_on_unshelve(sender, instance, *args, **kwargs): # ---- TASKS -@app.task +@app.task(queue="low_priority") def add_book_statuses_task(user_id, book_id): """add statuses related to a book on shelve""" user = models.User.objects.get(id=user_id) @@ -403,7 +403,7 @@ def add_book_statuses_task(user_id, book_id): BooksStream().add_book_statuses(user, book) -@app.task +@app.task(queue="low_priority") def remove_book_statuses_task(user_id, book_id): """remove statuses about a book from a user's books feed""" user = models.User.objects.get(id=user_id) @@ -411,7 +411,7 @@ def remove_book_statuses_task(user_id, book_id): BooksStream().remove_book_statuses(user, book) -@app.task +@app.task(queue="medium_priority") def populate_stream_task(stream, user_id): """background task for populating an empty activitystream""" user = models.User.objects.get(id=user_id) @@ -419,7 +419,7 @@ def populate_stream_task(stream, user_id): stream.populate_streams(user) -@app.task +@app.task(queue="medium_priority") def remove_status_task(status_ids): """remove a status from any stream it might be in""" # this can take an id or a list of ids @@ -432,7 +432,7 @@ def remove_status_task(status_ids): stream.remove_object_from_related_stores(status) -@app.task +@app.task(queue="medium_priority") def add_status_task(status_id, increment_unread=False): """remove a status from any stream it might be in""" status = models.Status.objects.get(id=status_id) @@ -440,7 +440,7 @@ def add_status_task(status_id, increment_unread=False): stream.add_status(status, increment_unread=increment_unread) -@app.task +@app.task(queue="medium_priority") def remove_user_statuses_task(viewer_id, user_id, stream_list=None): """remove all statuses by a user from a viewer's stream""" stream_list = [streams[s] for s in stream_list] if stream_list else streams.values() @@ -450,9 +450,9 @@ def remove_user_statuses_task(viewer_id, user_id, stream_list=None): stream.remove_user_statuses(viewer, user) -@app.task +@app.task(queue="medium_priority") def add_user_statuses_task(viewer_id, user_id, stream_list=None): - """remove all statuses by a user from a viewer's stream""" + """add all statuses by a user to a viewer's stream""" stream_list = [streams[s] for s in stream_list] if stream_list else streams.values() viewer = models.User.objects.get(id=viewer_id) user = models.User.objects.get(id=user_id) @@ -460,7 +460,7 @@ def add_user_statuses_task(viewer_id, user_id, stream_list=None): stream.add_user_statuses(viewer, user) -@app.task +@app.task(queue="medium_priority") def handle_boost_task(boost_id): """remove the original post and other, earlier boosts""" instance = models.Status.objects.get(id=boost_id) diff --git a/bookwyrm/connectors/connector_manager.py b/bookwyrm/connectors/connector_manager.py index 1a615c9b2..1d9588d6b 100644 --- a/bookwyrm/connectors/connector_manager.py +++ b/bookwyrm/connectors/connector_manager.py @@ -119,7 +119,7 @@ def get_or_create_connector(remote_id): return load_connector(connector_info) -@app.task +@app.task(queue="low_priority") def load_more_data(connector_id, book_id): """background the work of getting all 10,000 editions of LoTR""" connector_info = models.Connector.objects.get(id=connector_id) diff --git a/bookwyrm/emailing.py b/bookwyrm/emailing.py index fff3985ef..4f43c69e6 100644 --- a/bookwyrm/emailing.py +++ b/bookwyrm/emailing.py @@ -64,7 +64,7 @@ def format_email(email_name, data): return (subject, html_content, text_content) -@app.task +@app.task(queue="high_priority") def send_email(recipient, subject, html_content, text_content): """use a task to send the email""" email = EmailMultiAlternatives( diff --git a/bookwyrm/importers/importer.py b/bookwyrm/importers/importer.py index d5f1449ca..0968cdd79 100644 --- a/bookwyrm/importers/importer.py +++ b/bookwyrm/importers/importer.py @@ -61,7 +61,7 @@ class Importer: job.save() -@app.task +@app.task(queue="low_priority") def import_data(source, job_id): """does the actual lookup work in a celery task""" job = ImportJob.objects.get(id=job_id) diff --git a/bookwyrm/models/activitypub_mixin.py b/bookwyrm/models/activitypub_mixin.py index f287b752f..ed51158bc 100644 --- a/bookwyrm/models/activitypub_mixin.py +++ b/bookwyrm/models/activitypub_mixin.py @@ -502,7 +502,7 @@ def unfurl_related_field(related_field, sort_field=None): return related_field.remote_id -@app.task +@app.task(queue="medium_priority") def broadcast_task(sender_id, activity, recipients): """the celery task for broadcast""" user_model = apps.get_model("bookwyrm.User", require_ready=True) diff --git a/bookwyrm/models/import_job.py b/bookwyrm/models/import_job.py index 05aada161..69d5f5da7 100644 --- a/bookwyrm/models/import_job.py +++ b/bookwyrm/models/import_job.py @@ -174,6 +174,7 @@ class ImportItem(models.Model): if start_date and start_date is not None and not self.date_read: return [ReadThrough(start_date=start_date)] if self.date_read: + start_date = start_date if start_date < self.date_read else None return [ ReadThrough( start_date=start_date, diff --git a/bookwyrm/models/user.py b/bookwyrm/models/user.py index 0745dffa2..4b03f6656 100644 --- a/bookwyrm/models/user.py +++ b/bookwyrm/models/user.py @@ -274,30 +274,46 @@ class User(OrderedCollectionPageMixin, AbstractUser): transaction.on_commit(lambda: set_remote_server.delay(self.id)) return - # populate fields for local users - link = site_link() - self.remote_id = f"{link}/user/{self.localname}" - self.followers_url = f"{self.remote_id}/followers" - self.inbox = f"{self.remote_id}/inbox" - self.shared_inbox = f"{link}/inbox" - self.outbox = f"{self.remote_id}/outbox" + with transaction.atomic(): + # populate fields for local users + link = site_link() + self.remote_id = f"{link}/user/{self.localname}" + self.followers_url = f"{self.remote_id}/followers" + self.inbox = f"{self.remote_id}/inbox" + self.shared_inbox = f"{link}/inbox" + self.outbox = f"{self.remote_id}/outbox" - # an id needs to be set before we can proceed with related models + # an id needs to be set before we can proceed with related models + super().save(*args, **kwargs) + + # make users editors by default + try: + self.groups.add(Group.objects.get(name="editor")) + except Group.DoesNotExist: + # this should only happen in tests + pass + + # create keys and shelves for new local users + self.key_pair = KeyPair.objects.create( + remote_id=f"{self.remote_id}/#main-key" + ) + self.save(broadcast=False, update_fields=["key_pair"]) + + self.create_shelves() + + def delete(self, *args, **kwargs): + """deactivate rather than delete a user""" + self.is_active = False + # skip the logic in this class's save() super().save(*args, **kwargs) - # make users editors by default - try: - self.groups.add(Group.objects.get(name="editor")) - except Group.DoesNotExist: - # this should only happen in tests - pass - - # create keys and shelves for new local users - self.key_pair = KeyPair.objects.create( - remote_id="%s/#main-key" % self.remote_id - ) - self.save(broadcast=False, update_fields=["key_pair"]) + @property + def local_path(self): + """this model doesn't inherit bookwyrm model, so here we are""" + return "/user/%s" % (self.localname or self.username) + def create_shelves(self): + """default shelves for a new user""" shelves = [ { "name": "To Read", @@ -321,17 +337,6 @@ class User(OrderedCollectionPageMixin, AbstractUser): editable=False, ).save(broadcast=False) - def delete(self, *args, **kwargs): - """deactivate rather than delete a user""" - self.is_active = False - # skip the logic in this class's save() - super().save(*args, **kwargs) - - @property - def local_path(self): - """this model doesn't inherit bookwyrm model, so here we are""" - return "/user/%s" % (self.localname or self.username) - class KeyPair(ActivitypubMixin, BookWyrmModel): """public and private keys for a user""" @@ -420,7 +425,7 @@ class AnnualGoal(BookWyrmModel): } -@app.task +@app.task(queue="low_priority") def set_remote_server(user_id): """figure out the user's remote server in the background""" user = User.objects.get(id=user_id) @@ -459,7 +464,7 @@ def get_or_create_remote_server(domain): return server -@app.task +@app.task(queue="low_priority") def get_remote_reviews(outbox): """ingest reviews by a new remote bookwyrm user""" outbox_page = outbox + "?page=true&type=Review" diff --git a/bookwyrm/preview_images.py b/bookwyrm/preview_images.py index 4f85bb56e..900a3e123 100644 --- a/bookwyrm/preview_images.py +++ b/bookwyrm/preview_images.py @@ -352,7 +352,7 @@ def save_and_cleanup(image, instance=None): # pylint: disable=invalid-name -@app.task +@app.task(queue="low_priority") def generate_site_preview_image_task(): """generate preview_image for the website""" if not settings.ENABLE_PREVIEW_IMAGES: @@ -377,7 +377,7 @@ def generate_site_preview_image_task(): # pylint: disable=invalid-name -@app.task +@app.task(queue="low_priority") def generate_edition_preview_image_task(book_id): """generate preview_image for a book""" if not settings.ENABLE_PREVIEW_IMAGES: @@ -402,7 +402,7 @@ def generate_edition_preview_image_task(book_id): save_and_cleanup(image, instance=book) -@app.task +@app.task(queue="low_priority") def generate_user_preview_image_task(user_id): """generate preview_image for a book""" if not settings.ENABLE_PREVIEW_IMAGES: diff --git a/bookwyrm/settings.py b/bookwyrm/settings.py index c1f900794..9450ba81f 100644 --- a/bookwyrm/settings.py +++ b/bookwyrm/settings.py @@ -13,17 +13,6 @@ VERSION = "0.0.1" PAGE_LENGTH = env("PAGE_LENGTH", 15) DEFAULT_LANGUAGE = env("DEFAULT_LANGUAGE", "English") -# celery -CELERY_BROKER = "redis://:{}@redis_broker:{}/0".format( - requests.utils.quote(env("REDIS_BROKER_PASSWORD", "")), env("REDIS_BROKER_PORT") -) -CELERY_RESULT_BACKEND = "redis://:{}@redis_broker:{}/0".format( - requests.utils.quote(env("REDIS_BROKER_PASSWORD", "")), env("REDIS_BROKER_PORT") -) -CELERY_ACCEPT_CONTENT = ["application/json"] -CELERY_TASK_SERIALIZER = "json" -CELERY_RESULT_SERIALIZER = "json" - # email EMAIL_BACKEND = env("EMAIL_BACKEND", "django.core.mail.backends.smtp.EmailBackend") EMAIL_HOST = env("EMAIL_HOST") diff --git a/bookwyrm/static/css/bookwyrm.css b/bookwyrm/static/css/bookwyrm.css index 0724c7f14..3529afc2b 100644 --- a/bookwyrm/static/css/bookwyrm.css +++ b/bookwyrm/static/css/bookwyrm.css @@ -96,7 +96,7 @@ body { @see https://www.youtube.com/watch?v=9xXBYcWgCHA */ .shelf-option:disabled > *::after { font-family: "icomoon"; /* stylelint-disable font-family-no-missing-generic-family-keyword */ - content: "\e918"; + content: "\e919"; /* icon-check */ margin-left: 0.5em; } @@ -167,21 +167,21 @@ body { /* All stars are visually filled by default. */ .form-rate-stars .icon::before { - content: '\e9d9'; + content: '\e9d9'; /* icon-star-full */ } /* Icons directly following inputs that follow the checked input are emptied. */ .form-rate-stars input:checked ~ input + .icon::before { - content: '\e9d7'; + content: '\e9d7'; /* icon-star-empty */ } /* When a label is hovered, repeat the fill-all-then-empty-following pattern. */ .form-rate-stars:hover .icon.icon::before { - content: '\e9d9'; + content: '\e9d9'; /* icon-star-full */ } .form-rate-stars .icon:hover ~ .icon::before { - content: '\e9d7'; + content: '\e9d7'; /* icon-star-empty */ } /** Book covers @@ -292,13 +292,13 @@ body { } .quote > blockquote::before { - content: "\e906"; + content: "\e907"; /* icon-quote-open */ top: 0; left: 0; } .quote > blockquote::after { - content: "\e905"; + content: "\e906"; /* icon-quote-close */ right: 0; } diff --git a/bookwyrm/static/css/fonts/icomoon.eot b/bookwyrm/static/css/fonts/icomoon.eot index 2c801b2b6..12526617a 100644 Binary files a/bookwyrm/static/css/fonts/icomoon.eot and b/bookwyrm/static/css/fonts/icomoon.eot differ diff --git a/bookwyrm/static/css/fonts/icomoon.svg b/bookwyrm/static/css/fonts/icomoon.svg index 6327b19e6..765815843 100644 --- a/bookwyrm/static/css/fonts/icomoon.svg +++ b/bookwyrm/static/css/fonts/icomoon.svg @@ -7,34 +7,34 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/bookwyrm/static/css/fonts/icomoon.ttf b/bookwyrm/static/css/fonts/icomoon.ttf index 242ca7392..b0567ff8f 100644 Binary files a/bookwyrm/static/css/fonts/icomoon.ttf and b/bookwyrm/static/css/fonts/icomoon.ttf differ diff --git a/bookwyrm/static/css/fonts/icomoon.woff b/bookwyrm/static/css/fonts/icomoon.woff index 67b0f0a69..60d1742c1 100644 Binary files a/bookwyrm/static/css/fonts/icomoon.woff and b/bookwyrm/static/css/fonts/icomoon.woff differ diff --git a/bookwyrm/static/css/vendor/icons.css b/bookwyrm/static/css/vendor/icons.css index db783c24f..e9216e240 100644 --- a/bookwyrm/static/css/vendor/icons.css +++ b/bookwyrm/static/css/vendor/icons.css @@ -1,10 +1,10 @@ @font-face { font-family: 'icomoon'; - src: url('../fonts/icomoon.eot?19nagi'); - src: url('../fonts/icomoon.eot?19nagi#iefix') format('embedded-opentype'), - url('../fonts/icomoon.ttf?19nagi') format('truetype'), - url('../fonts/icomoon.woff?19nagi') format('woff'), - url('../fonts/icomoon.svg?19nagi#icomoon') format('svg'); + src: url('../fonts/icomoon.eot?wjd7rd'); + src: url('../fonts/icomoon.eot?wjd7rd#iefix') format('embedded-opentype'), + url('../fonts/icomoon.ttf?wjd7rd') format('truetype'), + url('../fonts/icomoon.woff?wjd7rd') format('woff'), + url('../fonts/icomoon.svg?wjd7rd#icomoon') format('svg'); font-weight: normal; font-style: normal; font-display: block; @@ -25,6 +25,90 @@ -moz-osx-font-smoothing: grayscale; } +.icon-book:before { + content: "\e901"; +} +.icon-envelope:before { + content: "\e902"; +} +.icon-arrow-right:before { + content: "\e903"; +} +.icon-bell:before { + content: "\e904"; +} +.icon-x:before { + content: "\e905"; +} +.icon-quote-close:before { + content: "\e906"; +} +.icon-quote-open:before { + content: "\e907"; +} +.icon-image:before { + content: "\e908"; +} +.icon-pencil:before { + content: "\e909"; +} +.icon-list:before { + content: "\e90a"; +} +.icon-unlock:before { + content: "\e90b"; +} +.icon-globe:before { + content: "\e90c"; +} +.icon-lock:before { + content: "\e90d"; +} +.icon-chain-broken:before { + content: "\e90e"; +} +.icon-chain:before { + content: "\e90f"; +} +.icon-comments:before { + content: "\e910"; +} +.icon-comment:before { + content: "\e911"; +} +.icon-boost:before { + content: "\e912"; +} +.icon-arrow-left:before { + content: "\e913"; +} +.icon-arrow-up:before { + content: "\e914"; +} +.icon-arrow-down:before { + content: "\e915"; +} +.icon-local:before { + content: "\e917"; +} +.icon-dots-three:before { + content: "\e918"; +} +.icon-check:before { + content: "\e919"; +} +.icon-dots-three-vertical:before { + content: "\e91a"; +} +.icon-bookmark:before { + content: "\e91b"; +} +.icon-warning:before { + content: "\e91c"; +} +.icon-rss:before { + content: "\e91d"; +} .icon-graphic-heart:before { content: "\e91e"; } @@ -34,102 +118,6 @@ .icon-graphic-banknote:before { content: "\e920"; } -.icon-warning:before { - content: "\e91b"; -} -.icon-book:before { - content: "\e900"; -} -.icon-bookmark:before { - content: "\e91a"; -} -.icon-rss:before { - content: "\e91d"; -} -.icon-envelope:before { - content: "\e901"; -} -.icon-arrow-right:before { - content: "\e902"; -} -.icon-bell:before { - content: "\e903"; -} -.icon-x:before { - content: "\e904"; -} -.icon-quote-close:before { - content: "\e905"; -} -.icon-quote-open:before { - content: "\e906"; -} -.icon-image:before { - content: "\e907"; -} -.icon-pencil:before { - content: "\e908"; -} -.icon-list:before { - content: "\e909"; -} -.icon-unlock:before { - content: "\e90a"; -} -.icon-unlisted:before { - content: "\e90a"; -} -.icon-globe:before { - content: "\e90b"; -} -.icon-public:before { - content: "\e90b"; -} -.icon-lock:before { - content: "\e90c"; -} -.icon-followers:before { - content: "\e90c"; -} -.icon-chain-broken:before { - content: "\e90d"; -} -.icon-chain:before { - content: "\e90e"; -} -.icon-comments:before { - content: "\e90f"; -} -.icon-comment:before { - content: "\e910"; -} -.icon-boost:before { - content: "\e911"; -} -.icon-arrow-left:before { - content: "\e912"; -} -.icon-arrow-up:before { - content: "\e913"; -} -.icon-arrow-down:before { - content: "\e914"; -} -.icon-home:before { - content: "\e915"; -} -.icon-local:before { - content: "\e916"; -} -.icon-dots-three:before { - content: "\e917"; -} -.icon-check:before { - content: "\e918"; -} -.icon-dots-three-vertical:before { - content: "\e919"; -} .icon-search:before { content: "\e986"; } @@ -148,3 +136,6 @@ .icon-plus:before { content: "\ea0a"; } +.icon-question-circle:before { + content: "\e900"; +} diff --git a/bookwyrm/suggested_users.py b/bookwyrm/suggested_users.py index 9c42d79d8..92902938a 100644 --- a/bookwyrm/suggested_users.py +++ b/bookwyrm/suggested_users.py @@ -194,27 +194,27 @@ def add_new_user(sender, instance, created, update_fields=None, **kwargs): remove_user_task.delay(instance.id) -@app.task +@app.task(queue="low_priority") def rerank_suggestions_task(user_id): """do the hard work in celery""" suggested_users.rerank_user_suggestions(user_id) -@app.task +@app.task(queue="low_priority") def rerank_user_task(user_id, update_only=False): """do the hard work in celery""" user = models.User.objects.get(id=user_id) suggested_users.rerank_obj(user, update_only=update_only) -@app.task +@app.task(queue="low_priority") def remove_user_task(user_id): """do the hard work in celery""" user = models.User.objects.get(id=user_id) suggested_users.remove_object_from_related_stores(user) -@app.task +@app.task(queue="medium_priority") 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) diff --git a/bookwyrm/tasks.py b/bookwyrm/tasks.py index 6d1992a77..b860e0184 100644 --- a/bookwyrm/tasks.py +++ b/bookwyrm/tasks.py @@ -2,10 +2,10 @@ import os from celery import Celery -from bookwyrm import settings +from celerywyrm import settings # set the default Django settings module for the 'celery' program. os.environ.setdefault("DJANGO_SETTINGS_MODULE", "celerywyrm.settings") app = Celery( - "tasks", broker=settings.CELERY_BROKER, backend=settings.CELERY_RESULT_BACKEND + "tasks", broker=settings.CELERY_BROKER_URL, backend=settings.CELERY_RESULT_BACKEND ) diff --git a/bookwyrm/templates/components/tooltip.html b/bookwyrm/templates/components/tooltip.html new file mode 100644 index 000000000..06b13f344 --- /dev/null +++ b/bookwyrm/templates/components/tooltip.html @@ -0,0 +1,11 @@ +{% load i18n %} + +{% trans "Help" as button_text %} +{% include 'snippets/toggle/open_button.html' with text=button_text class="ml-3 is-rounded is-small is-white p-0 pb-1" icon="question-circle is-size-6" controls_text=controls_text controls_uid=controls_uid %} + + diff --git a/bookwyrm/templates/import.html b/bookwyrm/templates/import/import.html similarity index 89% rename from bookwyrm/templates/import.html rename to bookwyrm/templates/import/import.html index d2e407486..cc296b75b 100644 --- a/bookwyrm/templates/import.html +++ b/bookwyrm/templates/import/import.html @@ -12,9 +12,14 @@
- + +
+ + {% include 'import/tooltip.html' with controls_text="goodreads-tooltip" %} +
+