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 "Impressum" %}

+
+ {{ site.impressum | safe }} +
+
+ +{% endblock %} diff --git a/bookwyrm/templates/about/layout.html b/bookwyrm/templates/about/layout.html index e921fcd29..22237508c 100644 --- a/bookwyrm/templates/about/layout.html +++ b/bookwyrm/templates/about/layout.html @@ -47,6 +47,14 @@ {% trans "Privacy Policy" %} + {% if site.show_impressum %} +
  • + {% url 'impressum' as path %} + + {% trans "Impressum" %} + +
  • + {% endif %} diff --git a/bookwyrm/templates/annual_summary/layout.html b/bookwyrm/templates/annual_summary/layout.html index 3d1796250..8d399c212 100644 --- a/bookwyrm/templates/annual_summary/layout.html +++ b/bookwyrm/templates/annual_summary/layout.html @@ -53,7 +53,7 @@ {% trans "Share this page" %} -
    +
    {% if year_key %} @@ -123,16 +123,18 @@

    {% 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 %}
    {% if details %} @@ -81,6 +81,14 @@
    {% endif %} + {% if author.isfdb %} + + {% endif %} + {% trans "Load data" as button_text %} {% if author.openlibrary_key %}
    @@ -128,6 +136,14 @@
    {% endif %} + + {% if author.isfdb %} +
    + + {% trans "View ISFDB entry" %} + +
    + {% endif %}
    {% endif %} @@ -144,7 +160,7 @@ {% for book in books %} {% with book=book|author_edition:author %}
    -
    +
    {% include 'landing/small-book.html' with book=book %}
    {% include 'snippets/shelve_button/shelve_button.html' with book=book %} diff --git a/bookwyrm/templates/author/edit_author.html b/bookwyrm/templates/author/edit_author.html index b0727c43b..1916df6be 100644 --- a/bookwyrm/templates/author/edit_author.html +++ b/bookwyrm/templates/author/edit_author.html @@ -101,6 +101,13 @@ {% include 'snippets/form_errors.html' with errors_list=form.goodreads_key.errors id="desc_goodreads_key" %}
    +
    + + {{ form.isfdb }} + + {% include 'snippets/form_errors.html' with errors_list=form.isfdb.errors id="desc_isfdb" %} +
    +
    {{ form.isni }} diff --git a/bookwyrm/templates/book/book.html b/bookwyrm/templates/book/book.html index 95829ae9d..6a8d4d794 100644 --- a/bookwyrm/templates/book/book.html +++ b/bookwyrm/templates/book/book.html @@ -25,7 +25,7 @@
    -

    +

    {{ book.title }}

    @@ -37,7 +37,7 @@ content="{{ book.subtitle | escape }}" > - + {{ book.subtitle }} {% endif %} @@ -52,7 +52,7 @@ {% endif %} {% if book.authors.exists %} -
    +
    {% trans "by" %} {% include 'snippets/authors.html' with book=book %}
    {% endif %} @@ -135,7 +135,7 @@ {% trans "View on OpenLibrary" %} {% if request.user.is_authenticated and perms.bookwyrm.edit_book %} - @@ -150,7 +150,7 @@ {% if request.user.is_authenticated and perms.bookwyrm.edit_book %} - @@ -158,6 +158,13 @@ {% endif %}

    {% endif %} + {% if book.isfdb %} +

    + + {% trans "View on ISFDB" %} + +

    + {% endif %}
    @@ -189,15 +196,15 @@ {% if user_authenticated and can_edit_book and not book|book_description %} {% trans 'Add Description' as button_text %} - {% include 'snippets/toggle/open_button.html' with text=button_text controls_text="add_description" controls_uid=book.id focus="id_description" hide_active=True id="hide_description" %} + {% include 'snippets/toggle/open_button.html' with class="mb-2" text=button_text controls_text="add_description" controls_uid=book.id focus="id_description" hide_active=True id="hide_description" %} diff --git a/bookwyrm/templates/email/test/html_content.html b/bookwyrm/templates/email/test/html_content.html new file mode 100644 index 000000000..7cf577f45 --- /dev/null +++ b/bookwyrm/templates/email/test/html_content.html @@ -0,0 +1,12 @@ +{% extends 'email/html_layout.html' %} +{% load i18n %} + +{% block content %} +

    +{% blocktrans trimmed %} +This is a test email. +{% endblocktrans %} +

    + + +{% endblock %} diff --git a/bookwyrm/templates/email/test/subject.html b/bookwyrm/templates/email/test/subject.html new file mode 100644 index 000000000..6ddada523 --- /dev/null +++ b/bookwyrm/templates/email/test/subject.html @@ -0,0 +1,4 @@ +{% load i18n %} +{% blocktrans trimmed %} +Test email +{% endblocktrans %} diff --git a/bookwyrm/templates/email/test/text_content.html b/bookwyrm/templates/email/test/text_content.html new file mode 100644 index 000000000..9d8a8f685 --- /dev/null +++ b/bookwyrm/templates/email/test/text_content.html @@ -0,0 +1,9 @@ +{% extends 'email/text_layout.html' %} +{% load i18n %} +{% block content %} +{% blocktrans trimmed %} +This is a test email. +{% endblocktrans %} + + +{% endblock %} diff --git a/bookwyrm/templates/feed/status_types_filter.html b/bookwyrm/templates/feed/status_types_filter.html index 1a6255b6e..ff1e800f8 100644 --- a/bookwyrm/templates/feed/status_types_filter.html +++ b/bookwyrm/templates/feed/status_types_filter.html @@ -2,7 +2,7 @@ {% load i18n %} {% block filter %} - +
    {% for name, value in feed_status_types_options %} diff --git a/bookwyrm/templates/landing/layout.html b/bookwyrm/templates/landing/layout.html index bf0a6b2a1..e3cdf1bdf 100644 --- a/bookwyrm/templates/landing/layout.html +++ b/bookwyrm/templates/landing/layout.html @@ -73,7 +73,7 @@ {% if site.invite_request_question %}
    - + {% include 'snippets/form_errors.html' with errors_list=request_form.answer.errors id="desc_answer_register" %}
    {% endif %} diff --git a/bookwyrm/templates/layout.html b/bookwyrm/templates/layout.html index e58f65edd..81aaee575 100644 --- a/bookwyrm/templates/layout.html +++ b/bookwyrm/templates/layout.html @@ -13,6 +13,7 @@ + {% if preview_images_enabled is True %} diff --git a/bookwyrm/templates/lists/layout.html b/bookwyrm/templates/lists/layout.html index c194e2f5f..e61d72b56 100644 --- a/bookwyrm/templates/lists/layout.html +++ b/bookwyrm/templates/lists/layout.html @@ -12,12 +12,16 @@

    -
    +
    {% if request.user == list.user %} +
    {% trans "Edit List" as button_text %} {% include 'snippets/toggle/open_button.html' with text=button_text icon_with_text="pencil" controls_text="edit_list" focus="edit_list_header" %} +
    {% endif %} - {% include "lists/bookmark_button.html" with list=list %} +
    + {% include "lists/bookmark_button.html" with list=list %} +
    diff --git a/bookwyrm/templates/lists/list.html b/bookwyrm/templates/lists/list.html index cc9956ab5..6824f5007 100644 --- a/bookwyrm/templates/lists/list.html +++ b/bookwyrm/templates/lists/list.html @@ -51,7 +51,7 @@ {% endif %} {% if not items.object_list.exists %} -

    {% trans "This list is currently empty" %}

    +

    {% trans "This list is currently empty." %}

    {% else %}
      {% for item in items %} diff --git a/bookwyrm/templates/notifications/items/add.html b/bookwyrm/templates/notifications/items/add.html index 22cdbc30a..39e0c7ed0 100644 --- a/bookwyrm/templates/notifications/items/add.html +++ b/bookwyrm/templates/notifications/items/add.html @@ -65,7 +65,7 @@ {# This happens if the list item was deleted #} {% blocktrans trimmed %} {{ related_user }} - added added a book to one of your lists + added a book to one of your lists {% endblocktrans %} {% elif related_list.curation != "curated" %} diff --git a/bookwyrm/templates/preferences/2fa.html b/bookwyrm/templates/preferences/2fa.html index 27ef026fb..7db3c0bcb 100644 --- a/bookwyrm/templates/preferences/2fa.html +++ b/bookwyrm/templates/preferences/2fa.html @@ -44,7 +44,7 @@ {% csrf_token %}

      {% trans "Scan the QR code with your authentication app and then enter the code from your app below to confirm your app is set up." %}

      -
      +
      {{ qrcode | safe }}
      diff --git a/bookwyrm/templates/search/barcode_modal.html b/bookwyrm/templates/search/barcode_modal.html index 70481b20a..519adfd3b 100644 --- a/bookwyrm/templates/search/barcode_modal.html +++ b/bookwyrm/templates/search/barcode_modal.html @@ -1,48 +1,46 @@ -{% extends 'components/modal.html' %} -{% load i18n %} - -{% block modal-title %} - {% blocktrans %} - Scan Barcode - {% endblocktrans %} -{% endblock %} - -{% block modal-body %} -
      -
      -
      - -
      - -
      - -
      - - - - -
      -{% endblock %} - -{% block modal-footer %} - -{% endblock %} - - +{% extends 'components/modal.html' %} +{% load i18n %} + +{% block modal-title %} + {% blocktrans %} + Scan Barcode + {% endblocktrans %} +{% endblock %} + +{% block modal-body %} +
      +
      +
      + +
      + +
      + + + + +
      +{% endblock %} + +{% block modal-footer %} + +{% endblock %} + + diff --git a/bookwyrm/templates/search/book.html b/bookwyrm/templates/search/book.html index f44a55026..262dcf2f9 100644 --- a/bookwyrm/templates/search/book.html +++ b/bookwyrm/templates/search/book.html @@ -58,7 +58,7 @@
      -
      +
        {% for result in result_set.results %} diff --git a/bookwyrm/templates/settings/automod/rules.html b/bookwyrm/templates/settings/automod/rules.html index 128ff20b7..bb13a8d7a 100644 --- a/bookwyrm/templates/settings/automod/rules.html +++ b/bookwyrm/templates/settings/automod/rules.html @@ -145,7 +145,7 @@

        {% trans "Current Rules" %}

        -
        +
        {% trans "Show rules" %} ({{ rules.count }}) diff --git a/bookwyrm/templates/settings/email_config.html b/bookwyrm/templates/settings/email_config.html new file mode 100644 index 000000000..3b10761ec --- /dev/null +++ b/bookwyrm/templates/settings/email_config.html @@ -0,0 +1,96 @@ +{% extends 'settings/layout.html' %} +{% load humanize %} +{% load i18n %} +{% load celery_tags %} + +{% block title %}{% trans "Email Configuration" %}{% endblock %} + +{% block header %}{% trans "Email Configuration" %}{% endblock %} + +{% block panel %} + +{% if error %} +
        + + + {% trans "Error sending test email:" %} + {{ error }} + +
        +{% elif success %} +
        + + + {% trans "Successfully sent test email." %} + +
        +{% endif %} + +
        +
        +
        + {% trans "Email sender:" %} +
        +
        + {{ email_sender }} +
        + +
        + {% trans "Email backend:" %} +
        +
        + {{ email_backend }} +
        + +
        + {% trans "Host:" %} +
        +
        + {{ email_host }} +
        + +
        + {% trans "Host user:" %} +
        +
        + {% firstof email_host_user "-" %} +
        + +
        + {% trans "Port:" %} +
        +
        + {{ email_port }} +
        + +
        + {% trans "Use TLS:" %} +
        +
        + {{ email_use_tls|yesno }} +
        + +
        + {% trans "Use SSL:" %} +
        +
        + {{ email_use_ssl|yesno }} +
        +
        +
        +
        +

        + {% blocktrans trimmed with email=request.user.email %} + Send test email to {{ email }} + {% endblocktrans %} +

        + + {% csrf_token %} + + +
        + +{% endblock %} + diff --git a/bookwyrm/templates/settings/layout.html b/bookwyrm/templates/settings/layout.html index f195bf754..b87fdf974 100644 --- a/bookwyrm/templates/settings/layout.html +++ b/bookwyrm/templates/settings/layout.html @@ -81,12 +81,14 @@ {% url 'settings-imports' as url %} {% trans "Imports" %} -
      - {% endif %} {% if perms.bookwyrm.edit_instance_settings %} @@ -101,10 +103,21 @@ {% trans "Site Settings" %} {% block site-subtabs %}{% endblock %} +
    1. + {% if perms.bookwyrm.manage_registration %} + {% url 'settings-registration' as url %} + {% trans "Registration" %} + {% else %} + {% url 'settings-registration-limited' as url %} + {% trans "Registration" %} + {% endif %} +
    2. + {% if perms.bookwyrm.system_administration %}
    3. {% url 'settings-themes' as url %} {% trans "Themes" %}
    4. + {% endif %} {% endif %} diff --git a/bookwyrm/templates/settings/link_domains/link_domains.html b/bookwyrm/templates/settings/link_domains/link_domains.html index c6957f570..e418bf678 100644 --- a/bookwyrm/templates/settings/link_domains/link_domains.html +++ b/bookwyrm/templates/settings/link_domains/link_domains.html @@ -40,23 +40,23 @@
      -
      -
      +
      - + {% trans "View links" %} ({{ domain.links.count }}) -
      +
      {% include "settings/link_domains/link_table.html" with links=domain.links.all|slice:10 %}
      diff --git a/bookwyrm/templates/settings/registration.html b/bookwyrm/templates/settings/registration.html new file mode 100644 index 000000000..6126f6b92 --- /dev/null +++ b/bookwyrm/templates/settings/registration.html @@ -0,0 +1,83 @@ +{% extends 'settings/layout.html' %} +{% load i18n %} + +{% block title %}{% trans "Registration" %}{% endblock %} + +{% block header %}{% trans "Registration" %}{% endblock %} + +{% block panel %} +{% if success %} +
      + + + {% trans "Settings saved" %} + +
      +{% endif %} + +{% if form.errors %} +
      + + + {% trans "Unable to save settings" %} + +
      +{% endif %} + +
      + {% csrf_token %} +
      +
      + +
      +
      + +

      {% trans "(Recommended if registration is open)" %}

      +
      +
      + +
      +
      + + {{ form.invite_request_text }} + + {% include 'snippets/form_errors.html' with errors_list=form.invite_request_text.errors id="desc_invite_request_text" %} +
      +
      + +
      +
      + +
      +
      + + {{ form.registration_closed_text }} +
      +
      + +
      + +
      +
      +{% endblock %} + diff --git a/bookwyrm/templates/settings/registration_limited.html b/bookwyrm/templates/settings/registration_limited.html new file mode 100644 index 000000000..343afefbb --- /dev/null +++ b/bookwyrm/templates/settings/registration_limited.html @@ -0,0 +1,81 @@ +{% extends 'settings/layout.html' %} +{% load i18n %} + +{% block title %}{% trans "Registration" %}{% endblock %} + +{% block header %}{% trans "Registration" %}{% endblock %} + +{% block panel %} +{% if success %} +
      + + + {% trans "Settings saved" %} + +
      +{% endif %} + +{% if form.errors %} +
      + + + {% trans "Unable to save settings" %} + +
      +{% endif %} + +{% if site.allow_registration %} +
      + {% trans "Registration is enabled on this instance" %} +
      +{% else %} +
      + {% csrf_token %} +
      + {% if site.allow_invite_requests %} +
      + + {{ form.invite_request_text }} + + {% include 'snippets/form_errors.html' with errors_list=form.invite_request_text.errors id="desc_invite_request_text" %} +
      +
      + +
      +
      + +
      + {% else %} + + + + {% endif %} + + {% if not site.allow_invite_requests and not site.allow_registration %} +
      + + {{ form.registration_closed_text }} +
      + {% else %} + + {% endif %} +
      + +
      + +
      +
      +{% endif %} +{% endblock %} + diff --git a/bookwyrm/templates/settings/site.html b/bookwyrm/templates/settings/site.html index 4fd147834..b6aef774a 100644 --- a/bookwyrm/templates/settings/site.html +++ b/bookwyrm/templates/settings/site.html @@ -10,7 +10,6 @@
    5. {% trans "Instance Info" %}
    6. {% trans "Display" %}
    7. {% trans "Footer Content" %}
    8. -
    9. {% trans "Registration" %}
    10. {% endblock %} @@ -68,6 +67,19 @@ {{ site_form.privacy_policy }}
      + +
      + + {{ site_form.impressum }} +
      +
      +
      + +
      +
      + {{ site_form.show_impressum }} +
      +
      @@ -128,55 +140,6 @@
      - - -
      -

      {% trans "Registration" %}

      -
      -
      - -
      -
      - -

      {% trans "(Recommended if registration is open)" %}

      -
      -
      - -
      -
      - -
      -
      - -
      -
      - - {{ site_form.registration_closed_text }} -
      -
      - - {{ site_form.invite_request_text }} - - {% include 'snippets/form_errors.html' with errors_list=site_form.invite_request_text.errors id="desc_invite_request_text" %} -
      -
      -
      -
      diff --git a/bookwyrm/templates/settings/users/delete_user_form.html b/bookwyrm/templates/settings/users/delete_user_form.html index 1ea63269d..eeb5e39fb 100644 --- a/bookwyrm/templates/settings/users/delete_user_form.html +++ b/bookwyrm/templates/settings/users/delete_user_form.html @@ -10,7 +10,7 @@ {% csrf_token %}

      {% blocktrans trimmed with username=user.localname %} - Are you sure you want to delete {{ username}}'s account? This action cannot be undone. To proceed, please enter your password to confirm deletion. + Are you sure you want to delete {{username}}'s account? This action cannot be undone. To proceed, please enter your password to confirm deletion. {% endblocktrans %}

      diff --git a/bookwyrm/templates/shelf/shelf.html b/bookwyrm/templates/shelf/shelf.html index 627ed98d5..8bd040e05 100644 --- a/bookwyrm/templates/shelf/shelf.html +++ b/bookwyrm/templates/shelf/shelf.html @@ -134,7 +134,7 @@ {% endif %}
      -
      +
      {% include 'shelf/edit_shelf_form.html' with controls_text="edit_shelf_form" %}
      diff --git a/bookwyrm/templates/snippets/filters_panel/filters_panel.html b/bookwyrm/templates/snippets/filters_panel/filters_panel.html index f0fe5d3f1..928b4f69b 100644 --- a/bookwyrm/templates/snippets/filters_panel/filters_panel.html +++ b/bookwyrm/templates/snippets/filters_panel/filters_panel.html @@ -25,7 +25,7 @@ -
      +
      {% if method == 'post' %} {% csrf_token %} @@ -34,7 +34,7 @@ {% if sort %} {% endif %} -
      +
      {% block filter_fields %} {% endblock %}
      diff --git a/bookwyrm/templates/snippets/footer.html b/bookwyrm/templates/snippets/footer.html index 77be88bfe..a1f13a5b8 100644 --- a/bookwyrm/templates/snippets/footer.html +++ b/bookwyrm/templates/snippets/footer.html @@ -29,6 +29,11 @@

      {% trans "Privacy Policy" %}

      + {% if site.show_impressum %} +

      + {% trans "Impressum" %} +

      + {% endif %}
      {% if site.support_link %} diff --git a/bookwyrm/templates/snippets/register_form.html b/bookwyrm/templates/snippets/register_form.html index 214e514c1..61e3b9c96 100644 --- a/bookwyrm/templates/snippets/register_form.html +++ b/bookwyrm/templates/snippets/register_form.html @@ -58,6 +58,8 @@
      + +