diff --git a/bookwyrm/activitypub/base_activity.py b/bookwyrm/activitypub/base_activity.py index fa845f124..095ec0227 100644 --- a/bookwyrm/activitypub/base_activity.py +++ b/bookwyrm/activitypub/base_activity.py @@ -194,6 +194,11 @@ class ActivityObject: try: if issubclass(type(v), ActivityObject): data[k] = v.serialize() + elif isinstance(v, list): + data[k] = [ + e.serialize() if issubclass(type(e), ActivityObject) else e + for e in v + ] except TypeError: pass data = {k: v for (k, v) in data.items() if v is not None and k not in omit} @@ -306,7 +311,9 @@ class Link(ActivityObject): def serialize(self, **kwargs): """remove fields""" - omit = ("id", "type", "@context") + omit = ("id", "@context") + if self.type == "Link": + omit += ("type",) return super().serialize(omit=omit) diff --git a/bookwyrm/activitypub/book.py b/bookwyrm/activitypub/book.py index e6a01b359..745aa3aab 100644 --- a/bookwyrm/activitypub/book.py +++ b/bookwyrm/activitypub/book.py @@ -19,6 +19,8 @@ class BookData(ActivityObject): viaf: str = None wikidata: str = None asin: str = None + aasin: str = None + isfdb: str = None lastEditedBy: str = None links: List[str] = field(default_factory=lambda: []) fileLinks: List[str] = field(default_factory=lambda: []) diff --git a/bookwyrm/emailing.py b/bookwyrm/emailing.py index 03cf4772e..2271077b1 100644 --- a/bookwyrm/emailing.py +++ b/bookwyrm/emailing.py @@ -18,6 +18,12 @@ def email_data(): } +def test_email(user): + """Just an admin checking if emails are sending""" + data = email_data() + send_email(user.email, *format_email("test", data)) + + def email_confirmation_email(user): """newly registered users confirm email address""" data = email_data() diff --git a/bookwyrm/forms/admin.py b/bookwyrm/forms/admin.py index ae15e011b..acff6cfaa 100644 --- a/bookwyrm/forms/admin.py +++ b/bookwyrm/forms/admin.py @@ -55,11 +55,45 @@ class CreateInviteForm(CustomForm): class SiteForm(CustomForm): class Meta: model = models.SiteSettings - exclude = ["admin_code", "install_mode"] + fields = [ + "name", + "instance_tagline", + "instance_description", + "instance_short_description", + "default_theme", + "code_of_conduct", + "privacy_policy", + "impressum", + "show_impressum", + "logo", + "logo_small", + "favicon", + "support_link", + "support_title", + "admin_email", + "footer_item", + ] widgets = { "instance_short_description": forms.TextInput( attrs={"aria-describedby": "desc_instance_short_description"} ), + } + + +class RegistrationForm(CustomForm): + class Meta: + model = models.SiteSettings + fields = [ + "allow_registration", + "allow_invite_requests", + "registration_closed_text", + "invite_request_text", + "invite_request_question", + "invite_question_text", + "require_confirm_email", + ] + + widgets = { "require_confirm_email": forms.CheckboxInput( attrs={"aria-describedby": "desc_require_confirm_email"} ), @@ -69,6 +103,23 @@ class SiteForm(CustomForm): } +class RegistrationLimitedForm(CustomForm): + class Meta: + model = models.SiteSettings + fields = [ + "registration_closed_text", + "invite_request_text", + "invite_request_question", + "invite_question_text", + ] + + widgets = { + "invite_request_text": forms.Textarea( + attrs={"aria-describedby": "desc_invite_request_text"} + ), + } + + class ThemeForm(CustomForm): class Meta: model = models.Theme diff --git a/bookwyrm/forms/author.py b/bookwyrm/forms/author.py index ca59426de..a7811180f 100644 --- a/bookwyrm/forms/author.py +++ b/bookwyrm/forms/author.py @@ -21,6 +21,7 @@ class AuthorForm(CustomForm): "inventaire_id", "librarything_key", "goodreads_key", + "isfdb", "isni", ] widgets = { diff --git a/bookwyrm/forms/books.py b/bookwyrm/forms/books.py index 9b3c84010..623beaa04 100644 --- a/bookwyrm/forms/books.py +++ b/bookwyrm/forms/books.py @@ -18,19 +18,30 @@ class CoverForm(CustomForm): class EditionForm(CustomForm): class Meta: model = models.Edition - exclude = [ - "remote_id", - "origin_id", - "created_date", - "updated_date", - "edition_rank", - "authors", - "parent_work", - "shelves", - "connector", - "search_vector", - "links", - "file_links", + fields = [ + "title", + "subtitle", + "description", + "series", + "series_number", + "languages", + "subjects", + "publishers", + "first_published_date", + "published_date", + "cover", + "physical_format", + "physical_format_detail", + "pages", + "isbn_13", + "isbn_10", + "openlibrary_key", + "inventaire_id", + "goodreads_key", + "oclc_number", + "asin", + "aasin", + "isfdb", ] widgets = { "title": forms.TextInput(attrs={"aria-describedby": "desc_title"}), @@ -73,10 +84,15 @@ class EditionForm(CustomForm): "inventaire_id": forms.TextInput( attrs={"aria-describedby": "desc_inventaire_id"} ), + "goodreads_key": forms.TextInput( + attrs={"aria-describedby": "desc_goodreads_key"} + ), "oclc_number": forms.TextInput( attrs={"aria-describedby": "desc_oclc_number"} ), "ASIN": forms.TextInput(attrs={"aria-describedby": "desc_ASIN"}), + "AASIN": forms.TextInput(attrs={"aria-describedby": "desc_AASIN"}), + "isfdb": forms.TextInput(attrs={"aria-describedby": "desc_isfdb"}), } diff --git a/bookwyrm/importers/importer.py b/bookwyrm/importers/importer.py index 95b34ec67..10bf453cd 100644 --- a/bookwyrm/importers/importer.py +++ b/bookwyrm/importers/importer.py @@ -17,8 +17,8 @@ class Importer: ("id", ["id", "book id"]), ("title", ["title"]), ("authors", ["author", "authors", "primary author"]), - ("isbn_10", ["isbn10", "isbn"]), - ("isbn_13", ["isbn13", "isbn", "isbns"]), + ("isbn_10", ["isbn10", "isbn", "isbn/uid"]), + ("isbn_13", ["isbn13", "isbn", "isbns", "isbn/uid"]), ("shelf", ["shelf", "exclusive shelf", "read status", "bookshelf"]), ("review_name", ["review name"]), ("review_body", ["my review", "review"]), diff --git a/bookwyrm/management/commands/confirm_email.py b/bookwyrm/management/commands/confirm_email.py new file mode 100644 index 000000000..450da7eec --- /dev/null +++ b/bookwyrm/management/commands/confirm_email.py @@ -0,0 +1,19 @@ +""" manually confirm e-mail of user """ +from django.core.management.base import BaseCommand + +from bookwyrm import models + + +class Command(BaseCommand): + """command-line options""" + + help = "Manually confirm email for user" + + def add_arguments(self, parser): + parser.add_argument("username") + + def handle(self, *args, **options): + name = options["username"] + user = models.User.objects.get(localname=name) + user.reactivate() + self.stdout.write(self.style.SUCCESS("User's email is now confirmed.")) diff --git a/bookwyrm/management/commands/initdb.py b/bookwyrm/management/commands/initdb.py index 23020a0a6..fda40bd07 100644 --- a/bookwyrm/management/commands/initdb.py +++ b/bookwyrm/management/commands/initdb.py @@ -8,54 +8,64 @@ from bookwyrm import models def init_groups(): """permission levels""" - groups = ["admin", "moderator", "editor"] + groups = ["admin", "owner", "moderator", "editor"] for group in groups: - Group.objects.create(name=group) + Group.objects.get_or_create(name=group) def init_permissions(): """permission types""" permissions = [ + { + "codename": "manage_registration", + "name": "allow or prevent user registration", + "groups": ["admin"], + }, + { + "codename": "system_administration", + "name": "technical controls", + "groups": ["admin"], + }, { "codename": "edit_instance_settings", "name": "change the instance info", - "groups": ["admin"], + "groups": ["admin", "owner"], }, { "codename": "set_user_group", "name": "change what group a user is in", - "groups": ["admin", "moderator"], + "groups": ["admin", "owner", "moderator"], }, { "codename": "control_federation", "name": "control who to federate with", - "groups": ["admin", "moderator"], + "groups": ["admin", "owner", "moderator"], }, { "codename": "create_invites", "name": "issue invitations to join", - "groups": ["admin", "moderator"], + "groups": ["admin", "owner", "moderator"], }, { "codename": "moderate_user", "name": "deactivate or silence a user", - "groups": ["admin", "moderator"], + "groups": ["admin", "owner", "moderator"], }, { "codename": "moderate_post", "name": "delete other users' posts", - "groups": ["admin", "moderator"], + "groups": ["admin", "owner", "moderator"], }, { "codename": "edit_book", "name": "edit book info", - "groups": ["admin", "moderator", "editor"], + "groups": ["admin", "owner", "moderator", "editor"], }, ] content_type = ContentType.objects.get_for_model(models.User) for permission in permissions: - permission_obj = Permission.objects.create( + permission_obj, _ = Permission.objects.get_or_create( codename=permission["codename"], name=permission["name"], content_type=content_type, diff --git a/bookwyrm/migrations/0167_auto_20221125_1900.py b/bookwyrm/migrations/0167_auto_20221125_1900.py new file mode 100644 index 000000000..db258b7c5 --- /dev/null +++ b/bookwyrm/migrations/0167_auto_20221125_1900.py @@ -0,0 +1,23 @@ +# Generated by Django 3.2.16 on 2022-11-25 19:00 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("bookwyrm", "0166_sitesettings_imports_enabled"), + ] + + operations = [ + migrations.AddField( + model_name="sitesettings", + name="impressum", + field=models.TextField(default="Add a impressum here."), + ), + migrations.AddField( + model_name="sitesettings", + name="show_impressum", + field=models.BooleanField(default=False), + ), + ] diff --git a/bookwyrm/migrations/0168_auto_20221205_1701.py b/bookwyrm/migrations/0168_auto_20221205_1701.py new file mode 100644 index 000000000..45d6c30e7 --- /dev/null +++ b/bookwyrm/migrations/0168_auto_20221205_1701.py @@ -0,0 +1,28 @@ +# Generated by Django 3.2.16 on 2022-12-05 17:01 + +import bookwyrm.models.fields +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ("bookwyrm", "0167_auto_20221125_1900"), + ] + + operations = [ + migrations.AddField( + model_name="author", + name="aasin", + field=bookwyrm.models.fields.CharField( + blank=True, max_length=255, null=True + ), + ), + migrations.AddField( + model_name="book", + name="aasin", + field=bookwyrm.models.fields.CharField( + blank=True, max_length=255, null=True + ), + ), + ] diff --git a/bookwyrm/migrations/0168_auto_20221205_2331.py b/bookwyrm/migrations/0168_auto_20221205_2331.py new file mode 100644 index 000000000..901ca56f0 --- /dev/null +++ b/bookwyrm/migrations/0168_auto_20221205_2331.py @@ -0,0 +1,63 @@ +""" I added two new permission types and a new group to the management command that +creates the database on install, this creates them for existing instances """ +# Generated by Django 3.2.16 on 2022-12-05 23:31 + +from django.db import migrations + + +def create_groups_and_perms(apps, schema_editor): + """create the new "owner" group and "system admin" permission""" + db_alias = schema_editor.connection.alias + group_model = apps.get_model("auth", "Group") + # Add the "owner" group, if needed + owner_group, group_created = group_model.objects.using(db_alias).get_or_create( + name="owner" + ) + + # Create perms, if needed + user_model = apps.get_model("bookwyrm", "User") + content_type_model = apps.get_model("contenttypes", "ContentType") + content_type = content_type_model.objects.get_for_model(user_model) + perms_model = apps.get_model("auth", "Permission") + reg_perm, perm_created = perms_model.objects.using(db_alias).get_or_create( + codename="manage_registration", + name="allow or prevent user registration", + content_type=content_type, + ) + admin_perm, admin_perm_created = perms_model.objects.using(db_alias).get_or_create( + codename="system_administration", + name="technical controls", + content_type=content_type, + ) + + # Add perms to the group if anything was created + if group_created or perm_created or admin_perm_created: + perms = [ + "edit_instance_settings", + "set_user_group", + "control_federation", + "create_invites", + "moderate_user", + "moderate_post", + "edit_book", + ] + owner_group.permissions.set( + perms_model.objects.using(db_alias).filter(codename__in=perms).all() + ) + + # also extend these perms to admins + # This is get or create so the tests don't fail -- it should already exist + admin_group, _ = group_model.objects.using(db_alias).get_or_create(name="admin") + admin_group.permissions.add(reg_perm) + admin_group.permissions.add(admin_perm) + + +class Migration(migrations.Migration): + + dependencies = [ + ("bookwyrm", "0167_auto_20221125_1900"), + ] + + operations = [ + migrations.RunPython(create_groups_and_perms, migrations.RunPython.noop) + ] diff --git a/bookwyrm/migrations/0169_auto_20221206_0902.py b/bookwyrm/migrations/0169_auto_20221206_0902.py new file mode 100644 index 000000000..7235490eb --- /dev/null +++ b/bookwyrm/migrations/0169_auto_20221206_0902.py @@ -0,0 +1,28 @@ +# Generated by Django 3.2.16 on 2022-12-06 09:02 + +import bookwyrm.models.fields +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ("bookwyrm", "0168_auto_20221205_1701"), + ] + + operations = [ + migrations.AddField( + model_name="author", + name="isfdb", + field=bookwyrm.models.fields.CharField( + blank=True, max_length=255, null=True + ), + ), + migrations.AddField( + model_name="book", + name="isfdb", + field=bookwyrm.models.fields.CharField( + blank=True, max_length=255, null=True + ), + ), + ] diff --git a/bookwyrm/migrations/0170_merge_0168_auto_20221205_2331_0169_auto_20221206_0902.py b/bookwyrm/migrations/0170_merge_0168_auto_20221205_2331_0169_auto_20221206_0902.py new file mode 100644 index 000000000..3e199b014 --- /dev/null +++ b/bookwyrm/migrations/0170_merge_0168_auto_20221205_2331_0169_auto_20221206_0902.py @@ -0,0 +1,13 @@ +# Generated by Django 3.2.16 on 2022-12-11 20:00 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ("bookwyrm", "0168_auto_20221205_2331"), + ("bookwyrm", "0169_auto_20221206_0902"), + ] + + operations = [] diff --git a/bookwyrm/models/author.py b/bookwyrm/models/author.py index 7d2a0e62b..de0c6483f 100644 --- a/bookwyrm/models/author.py +++ b/bookwyrm/models/author.py @@ -24,6 +24,9 @@ class Author(BookDataModel): gutenberg_id = fields.CharField( max_length=255, blank=True, null=True, deduplication_field=True ) + isfdb = fields.CharField( + max_length=255, blank=True, null=True, deduplication_field=True + ) # idk probably other keys would be useful here? born = fields.DateTimeField(blank=True, null=True) died = fields.DateTimeField(blank=True, null=True) @@ -60,6 +63,11 @@ class Author(BookDataModel): """generate the url from the openlibrary id""" return f"https://openlibrary.org/authors/{self.openlibrary_key}" + @property + def isfdb_link(self): + """generate the url from the isni id""" + return f"https://www.isfdb.org/cgi-bin/ea.cgi?{self.isfdb}" + def get_remote_id(self): """editions and works both use "book" instead of model_name""" return f"https://{DOMAIN}/author/{self.id}" diff --git a/bookwyrm/models/book.py b/bookwyrm/models/book.py index 5bef5c1ee..e990b6d64 100644 --- a/bookwyrm/models/book.py +++ b/bookwyrm/models/book.py @@ -55,6 +55,12 @@ class BookDataModel(ObjectMixin, BookWyrmModel): asin = fields.CharField( max_length=255, blank=True, null=True, deduplication_field=True ) + aasin = fields.CharField( + max_length=255, blank=True, null=True, deduplication_field=True + ) + isfdb = fields.CharField( + max_length=255, blank=True, null=True, deduplication_field=True + ) search_vector = SearchVectorField(null=True) last_edited_by = fields.ForeignKey( @@ -73,6 +79,11 @@ class BookDataModel(ObjectMixin, BookWyrmModel): """generate the url from the inventaire id""" return f"https://inventaire.io/entity/{self.inventaire_id}" + @property + def isfdb_link(self): + """generate the url from the isfdb id""" + return f"https://www.isfdb.org/cgi-bin/title.cgi?{self.isfdb}" + class Meta: """can't initialize this model, that wouldn't make sense""" diff --git a/bookwyrm/models/fields.py b/bookwyrm/models/fields.py index 785f3397c..d11f5fb1d 100644 --- a/bookwyrm/models/fields.py +++ b/bookwyrm/models/fields.py @@ -13,6 +13,7 @@ from django.forms import ClearableFileInput, ImageField as DjangoImageField from django.utils import timezone from django.utils.translation import gettext_lazy as _ from django.utils.encoding import filepath_to_uri +from markdown import markdown from bookwyrm import activitypub from bookwyrm.connectors import get_image @@ -499,6 +500,9 @@ class HtmlField(ActivitypubFieldMixin, models.TextField): return None return clean(value) + def field_to_activity(self, value): + return markdown(value) if value else value + class ArrayField(ActivitypubFieldMixin, DjangoArrayField): """activitypub-aware array field""" diff --git a/bookwyrm/models/site.py b/bookwyrm/models/site.py index 78f35e39b..747565161 100644 --- a/bookwyrm/models/site.py +++ b/bookwyrm/models/site.py @@ -62,6 +62,8 @@ class SiteSettings(SiteModel): ) code_of_conduct = models.TextField(default="Add a code of conduct here.") privacy_policy = models.TextField(default="Add a privacy policy here.") + impressum = models.TextField(default="Add a impressum here.") + show_impressum = models.BooleanField(default=False) # registration allow_registration = models.BooleanField(default=False) diff --git a/bookwyrm/models/user.py b/bookwyrm/models/user.py index e48d86572..7df9da88d 100644 --- a/bookwyrm/models/user.py +++ b/bookwyrm/models/user.py @@ -373,6 +373,7 @@ class User(OrderedCollectionPageMixin, AbstractUser): """We don't actually delete the database entry""" # pylint: disable=attribute-defined-outside-init self.is_active = False + self.avatar = "" # skip the logic in this class's save() super().save(*args, **kwargs) @@ -390,7 +391,10 @@ class User(OrderedCollectionPageMixin, AbstractUser): self.is_active = True self.deactivation_reason = None self.allow_reactivation = False - super().save(broadcast=False) + super().save( + broadcast=False, + update_fields=["deactivation_reason", "is_active", "allow_reactivation"], + ) @property def local_path(self): diff --git a/bookwyrm/settings.py b/bookwyrm/settings.py index 1a3238a1f..0780f8c54 100644 --- a/bookwyrm/settings.py +++ b/bookwyrm/settings.py @@ -11,7 +11,7 @@ from django.utils.translation import gettext_lazy as _ env = Env() env.read_env() DOMAIN = env("DOMAIN") -VERSION = "0.5.2" +VERSION = "0.5.3" RELEASE_API = env( "RELEASE_API", @@ -21,7 +21,7 @@ RELEASE_API = env( PAGE_LENGTH = env("PAGE_LENGTH", 15) DEFAULT_LANGUAGE = env("DEFAULT_LANGUAGE", "English") -JS_CACHE = "e678183c" +JS_CACHE = "ad848b97" # email EMAIL_BACKEND = env("EMAIL_BACKEND", "django.core.mail.backends.smtp.EmailBackend") diff --git a/bookwyrm/static/css/bookwyrm/_all.scss b/bookwyrm/static/css/bookwyrm/_all.scss index 31e732ebe..1e8569827 100644 --- a/bookwyrm/static/css/bookwyrm/_all.scss +++ b/bookwyrm/static/css/bookwyrm/_all.scss @@ -140,6 +140,10 @@ button:focus-visible .button-invisible-overlay { opacity: 1; } +button.button-paragraph { + vertical-align: middle; +} + /** States ******************************************************************************/ diff --git a/bookwyrm/static/css/bookwyrm/components/_details.scss b/bookwyrm/static/css/bookwyrm/components/_details.scss index de29629c8..4145554eb 100644 --- a/bookwyrm/static/css/bookwyrm/components/_details.scss +++ b/bookwyrm/static/css/bookwyrm/components/_details.scss @@ -81,7 +81,19 @@ details.dropdown .dropdown-menu a:focus-visible { details.details-panel { box-shadow: 0 0 0 1px $border; transition: box-shadow 0.2s ease; - padding: 0.75rem; + padding: 0; + + > * { + padding: 0.75rem; + } + + summary { + position: relative; + + .details-close { + padding: 0.75rem; + } + } } details[open].details-panel, @@ -89,10 +101,6 @@ details.details-panel:hover { box-shadow: 0 0 0 1px $border; } -details.details-panel summary { - position: relative; -} - details summary .details-close { position: absolute; right: 0; diff --git a/bookwyrm/static/css/themes/bookwyrm-dark.scss b/bookwyrm/static/css/themes/bookwyrm-dark.scss index b98422688..ae904b4a4 100644 --- a/bookwyrm/static/css/themes/bookwyrm-dark.scss +++ b/bookwyrm/static/css/themes/bookwyrm-dark.scss @@ -15,6 +15,8 @@ $danger: #872538; $danger-light: #481922; $light: #393939; $red: #ffa1b4; +$black: #000; +$white-ter: hsl(0, 0%, 90%); /* book cover standins */ $no-cover-color: #002549; @@ -56,9 +58,12 @@ $link-active: $white-bis; $link-light: #0d1c26; /* bulma overrides */ +$body-background-color: rgb(17, 18, 18); $background: $background-secondary; $menu-item-active-background-color: $link-background; $navbar-dropdown-item-hover-color: $white; +$info-light: $background-body; +$info-dark: #72b6ee; /* These element's colors are hardcoded, probably a bug in bulma? */ @media screen and (min-width: 769px) { @@ -74,7 +79,7 @@ $navbar-dropdown-item-hover-color: $white; } /* misc */ -$shadow: 0 0.5em 1em -0.125em rgba($black, 0.2), 0 0px 0 1px rgba($black, 0.02); +$shadow: 0 0.5em 0.5em -0.125em rgba($black, 0.2), 0 0px 0 1px rgba($black, 0.02); $card-header-shadow: 0 0.125em 0.25em rgba($black, 0.1); $invisible-overlay-background-color: rgba($black, 0.66); $progress-value-background-color: $border-light; @@ -92,6 +97,7 @@ $family-secondary: $family-sans-serif; color: $grey-light !important; } + #qrcode svg { background-color: #a6a6a6; } diff --git a/bookwyrm/static/js/bookwyrm.js b/bookwyrm/static/js/bookwyrm.js index aa06a8b0a..dee4231b8 100644 --- a/bookwyrm/static/js/bookwyrm.js +++ b/bookwyrm/static/js/bookwyrm.js @@ -48,6 +48,12 @@ let BookWyrm = new (class { document .querySelector("#barcode-scanner-modal") .addEventListener("open", this.openBarcodeScanner.bind(this)); + + document + .querySelectorAll('form[name="register"]') + .forEach((form) => + form.addEventListener("submit", (e) => this.setPreferredTimezone(e, form)) + ); } /** @@ -628,9 +634,9 @@ let BookWyrm = new (class { } function toggleStatus(status) { - for (const child of statusNode.children) { - BookWyrm.toggleContainer(child, !child.classList.contains(status)); - } + const template = document.querySelector(`#barcode-${status}`); + + statusNode.replaceChildren(template ? template.content.cloneNode(true) : null); } function initBarcodes(cameraId = null) { @@ -785,4 +791,16 @@ let BookWyrm = new (class { initBarcodes(); } + + /** + * Set preferred timezone in register form. + * + * @param {Event} event - `submit` event fired by the register form. + * @return {undefined} + */ + setPreferredTimezone(event, form) { + const tz = Intl.DateTimeFormat().resolvedOptions().timeZone; + + form.querySelector('input[name="preferred_timezone"]').value = tz; + } })(); diff --git a/bookwyrm/templates/about/impressum.html b/bookwyrm/templates/about/impressum.html new file mode 100644 index 000000000..3f892c7a7 --- /dev/null +++ b/bookwyrm/templates/about/impressum.html @@ -0,0 +1,15 @@ +{% extends 'about/layout.html' %} +{% load i18n %} + +{% block title %}{% trans "Impressum" %}{% endblock %} + + +{% block about_content %} +
{% trans "That’s great!" %}
-- {% blocktrans with pages=pages_average|intcomma %}That makes an average of {{ pages }} pages per book.{% endblocktrans %} -
+ {% if pages > 0 %} ++ {% blocktrans with pages=pages_average|intcomma %}That makes an average of {{ pages }} pages per book.{% endblocktrans %} +
+ {% endif %} {% if no_page_number %}{% blocktrans trimmed count counter=no_page_number %} - ({{ no_page_number }} book doesn’t have pages) + (No page data was available for {{ no_page_number }} book) {% plural %} - ({{ no_page_number }} books don’t have pages) + (No page data was available for {{ no_page_number }} books) {% endblocktrans %}
{% endif %} diff --git a/bookwyrm/templates/author/author.html b/bookwyrm/templates/author/author.html index f186c0f6e..ade654568 100644 --- a/bookwyrm/templates/author/author.html +++ b/bookwyrm/templates/author/author.html @@ -28,7 +28,7 @@ {% firstof author.aliases author.born author.died as details %} - {% firstof author.wikipedia_link author.openlibrary_key author.inventaire_id author.isni as links %} + {% firstof author.wikipedia_link author.openlibrary_key author.inventaire_id author.isni author.isfdb as links %} {% if details or links %}