diff --git a/.env.example b/.env.example index cf3705af..2397a5b1 100644 --- a/.env.example +++ b/.env.example @@ -36,3 +36,4 @@ EMAIL_PORT=587 EMAIL_HOST_USER=mail@your.domain.here EMAIL_HOST_PASSWORD=emailpassword123 EMAIL_USE_TLS=true +EMAIL_USE_SSL=false diff --git a/README.md b/README.md index e798fedf..dc3af920 100644 --- a/README.md +++ b/README.md @@ -156,24 +156,6 @@ The `production` branch of BookWyrm contains a number of tools not on the `main` Instructions for running BookWyrm in production: -- Get the application code: - `git clone git@github.com:mouse-reeve/bookwyrm.git` -- Switch to the `production` branch - `git checkout production` -- Create your environment variables file - `cp .env.example .env` - - Add your domain, email address, SMTP credentials - - Set a secure redis password and secret key - - Set a secure database password for postgres -- Update your nginx configuration in `nginx/default.conf` - - Replace `your-domain.com` with your domain name -- Run the application (this should also set up a Certbot ssl cert for your domain) with - `docker-compose up --build`, and make sure all the images build successfully -- When docker has built successfully, stop the process with `CTRL-C` -- Comment out the `command: certonly...` line in `docker-compose.yml` -- Run docker-compose in the background with: `docker-compose up -d` -- Initialize the database with: `./bw-dev initdb` -- Set up schedule backups with cron that runs that `docker-compose exec db pg_dump -U ` and saves the backup to a safe location - Get the application code: `git clone git@github.com:mouse-reeve/bookwyrm.git` - Switch to the `production` branch diff --git a/bookwyrm/migrations/0063_auto_20210408_1556.py b/bookwyrm/migrations/0063_auto_20210408_1556.py new file mode 100644 index 00000000..750997fb --- /dev/null +++ b/bookwyrm/migrations/0063_auto_20210408_1556.py @@ -0,0 +1,27 @@ +# Generated by Django 3.1.6 on 2021-04-08 15:56 + +import bookwyrm.models.fields +import django.contrib.postgres.fields.citext +import django.contrib.postgres.operations +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ("bookwyrm", "0062_auto_20210407_1545"), + ] + + operations = [ + django.contrib.postgres.operations.CITextExtension(), + migrations.AlterField( + model_name="user", + name="localname", + field=django.contrib.postgres.fields.citext.CICharField( + max_length=255, + null=True, + unique=True, + validators=[bookwyrm.models.fields.validate_localname], + ), + ), + ] diff --git a/bookwyrm/models/user.py b/bookwyrm/models/user.py index dcc4162e..c519f76c 100644 --- a/bookwyrm/models/user.py +++ b/bookwyrm/models/user.py @@ -4,6 +4,7 @@ from urllib.parse import urlparse from django.apps import apps from django.contrib.auth.models import AbstractUser, Group +from django.contrib.postgres.fields import CICharField from django.core.validators import MinValueValidator from django.db import models from django.utils import timezone @@ -54,7 +55,7 @@ class User(OrderedCollectionPageMixin, AbstractUser): summary = fields.HtmlField(null=True, blank=True) local = models.BooleanField(default=False) bookwyrm_user = fields.BooleanField(default=True) - localname = models.CharField( + localname = CICharField( max_length=255, null=True, unique=True, diff --git a/bookwyrm/settings.py b/bookwyrm/settings.py index 845f81c4..146d4fff 100644 --- a/bookwyrm/settings.py +++ b/bookwyrm/settings.py @@ -24,7 +24,8 @@ EMAIL_HOST = env("EMAIL_HOST") EMAIL_PORT = env("EMAIL_PORT", 587) EMAIL_HOST_USER = env("EMAIL_HOST_USER") EMAIL_HOST_PASSWORD = env("EMAIL_HOST_PASSWORD") -EMAIL_USE_TLS = env("EMAIL_USE_TLS", True) +EMAIL_USE_TLS = env.bool("EMAIL_USE_TLS", True) +EMAIL_USE_SSL = env.bool("EMAIL_USE_SSL", False) DEFAULT_FROM_EMAIL = "admin@{:s}".format(env("DOMAIN")) # Build paths inside the project like this: os.path.join(BASE_DIR, ...) diff --git a/bookwyrm/templates/book/book.html b/bookwyrm/templates/book/book.html index b91cebba..4d978d7e 100644 --- a/bookwyrm/templates/book/book.html +++ b/bookwyrm/templates/book/book.html @@ -6,24 +6,36 @@ {% block title %}{{ book.title }}{% endblock %} {% block content %} -
+{% with user_authenticated=request.user.is_authenticated can_edit_book=perms.bookwyrm.edit_book %} +

- {{ book.title }}{% if book.subtitle %}: - {{ book.subtitle }}{% endif %} + + {{ book.title }}{% if book.subtitle %}: + {{ book.subtitle }} + {% endif %} + + {% if book.series %} - ({{ book.series }}{% if book.series_number %} #{{ book.series_number }}{% endif %})
+ + + + + ({{ book.series }} + {% if book.series_number %} #{{ book.series_number }}{% endif %}) + +
{% endif %}

{% if book.authors %}

- {% trans "by" %} {% include 'snippets/authors.html' with book=book %} + {% trans "by" %} {% include 'snippets/authors.html' with book=book %}

{% endif %}
- {% if request.user.is_authenticated and perms.bookwyrm.edit_book %} + {% if user_authenticated and can_edit_book %} - {% if request.user.is_authenticated and not book.cover %} + {% if user_authenticated and not book.cover %}
{% trans "Add cover" as button_text %} {% include 'snippets/toggle/toggle_button.html' with text=button_text controls_text="add-cover" controls_uid=book.id focus="modal-title-add-cover" class="is-small" %} @@ -60,7 +72,7 @@ {% if book.isbn_13 %}
{% trans "ISBN:" %}
-
{{ book.isbn_13 }}
+
{{ book.isbn_13 }}
{% endif %} @@ -89,14 +101,31 @@
-

+

+ + {# @todo Is it possible to not hard-code the value? #} + + + {% include 'snippets/stars.html' with rating=rating %} - {% blocktrans count counter=review_count %}({{ review_count }} review){% plural %}({{ review_count }} reviews){% endblocktrans %} + + {% blocktrans count counter=review_count trimmed %} + ({{ review_count }} review) + {% plural %} + ({{ review_count }} reviews) + {% endblocktrans %}

- {% include 'snippets/trimmed_text.html' with full=book|book_description %} + {% with full=book|book_description itemprop='abstract' %} + {% include 'snippets/trimmed_text.html' %} + {% endwith %} - {% if request.user.is_authenticated and perms.bookwyrm.edit_book and not book|book_description %} + {% 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" %} @@ -138,7 +167,7 @@ {% endfor %}
- {% if request.user.is_authenticated %} + {% if user_authenticated %}

{% trans "Your reading activity" %}

@@ -176,14 +205,15 @@
{% if book.subjects %} -
-

{% trans "Subjects" %}

-
    - {% for subject in book.subjects %} -
  • {{ subject }}
  • - {% endfor %} -
-
+
+

{% trans "Subjects" %}

+ +
    + {% for subject in book.subjects %} +
  • {{ subject }}
  • + {% endfor %} +
+
{% endif %} {% if book.subject_places %} @@ -229,41 +259,54 @@ {% endif %}
-
-
- {% for review in reviews %} -
- {% include 'snippets/status/status.html' with status=review hide_book=True depth=1 %} -
- {% endfor %} - -
- {% for rating in ratings %} -
-
-
{% include 'snippets/avatar.html' with user=rating.user %}
-
- -
-

{% trans "rated it" %}

- {% include 'snippets/stars.html' with rating=rating.rating %} -
- -
+
+ {% for review in reviews %} +
+ {% with status=review hide_book=True depth=1 %} + {% include 'snippets/status/status.html' %} + {% endwith %}
-
{% endfor %} -
-
- {% include 'snippets/pagination.html' with page=reviews path=book.local_path anchor="#reviews" %} + +
+ {% for rating in ratings %} + {% with user=rating.user %} +
+
+
+ {% include 'snippets/avatar.html' %} +
+ +
+ +
+

{% trans "rated it" %}

+ + {% include 'snippets/stars.html' with rating=rating.rating %} +
+ +
+
+
+ {% endwith %} + {% endfor %} +
+
+ {% include 'snippets/pagination.html' with page=reviews path=book.local_path anchor="#reviews" %} +
- +{% endwith %} {% endblock %} {% block scripts %} diff --git a/bookwyrm/templates/book/edit_book.html b/bookwyrm/templates/book/edit_book.html index 15202d80..af5d4d69 100644 --- a/bookwyrm/templates/book/edit_book.html +++ b/bookwyrm/templates/book/edit_book.html @@ -90,7 +90,7 @@

{% trans "Metadata" %}

- +

{% for error in form.title.errors %}

{{ error | escape }}

@@ -98,7 +98,7 @@

- +

{% for error in form.subtitle.errors %}

{{ error | escape }}

@@ -130,7 +130,7 @@

- +

{% for error in form.first_published_date.errors %}

{{ error | escape }}

@@ -138,7 +138,7 @@

- +

{% for error in form.published_date.errors %}

{{ error | escape }}

diff --git a/bookwyrm/templates/book/publisher_info.html b/bookwyrm/templates/book/publisher_info.html index 0ab35401..a16332c5 100644 --- a/bookwyrm/templates/book/publisher_info.html +++ b/bookwyrm/templates/book/publisher_info.html @@ -1,24 +1,69 @@ +{% spaceless %} + {% load i18n %} +

- {% if book.physical_format and not book.pages %} - {{ book.physical_format | title }} - {% elif book.physical_format and book.pages %} - {% blocktrans with format=book.physical_format|title pages=book.pages %}{{ format }}, {{ pages }} pages{% endblocktrans %} - {% elif book.pages %} - {% blocktrans with pages=book.pages %}{{ pages }} pages{% endblocktrans %} - {% endif %} + {% with format=book.physical_format pages=book.pages %} + {% if format %} + {% comment %} + @todo The bookFormat property is limited to a list of values whereas the book edition is free text. + @see https://schema.org/bookFormat + {% endcomment %} + + {% endif %} + + {% if pages %} + + {% endif %} + + {% if format and not pages %} + {% blocktrans %}{{ format }}{% endblocktrans %} + {% elif format and pages %} + {% blocktrans %}{{ format }}, {{ pages }} pages{% endblocktrans %} + {% elif pages %} + {% blocktrans %}{{ pages }} pages{% endblocktrans %} + {% endif %} + {% endwith %}

+ {% if book.languages %} -

- {% blocktrans with languages=book.languages|join:", " %}{{ languages }} language{% endblocktrans %} -

+ {% for language in book.languages %} + + {% endfor %} + +

+ {% with languages=book.languages|join:", " %} + {% blocktrans %}{{ languages }} language{% endblocktrans %} + {% endwith %} +

{% endif %} +

- {% if book.published_date and book.publishers %} - {% blocktrans with date=book.published_date|date:'M jS Y' publisher=book.publishers|join:', ' %}Published {{ date }} by {{ publisher }}.{% endblocktrans %} - {% elif book.published_date %} - {% blocktrans with date=book.published_date|date:'M jS Y' %}Published {{ date }}{% endblocktrans %} - {% elif book.publishers %} - {% blocktrans with publisher=book.publishers|join:', ' %}Published by {{ publisher }}.{% endblocktrans %} - {% endif %} + {% with date=book.published_date|date:'M jS Y' publisher=book.publishers|join:', ' %} + {% if date or book.first_published_date %} + + {% endif %} + + {% comment %} + @todo The publisher property needs to be an Organization or a Person. We’ll be using Thing which is the more generic ancestor. + @see https://schema.org/Publisher + {% endcomment %} + {% if book.publishers %} + {% for publisher in book.publishers %} + + {% endfor %} + {% endif %} + + {% if date and publisher %} + {% blocktrans %}Published {{ date }} by {{ publisher }}.{% endblocktrans %} + {% elif date %} + {% blocktrans %}Published {{ date }}{% endblocktrans %} + {% elif publisher %} + {% blocktrans %}Published by {{ publisher }}.{% endblocktrans %} + {% endif %} + {% endwith %}

+{% endspaceless %} diff --git a/bookwyrm/templates/snippets/authors.html b/bookwyrm/templates/snippets/authors.html index dd94b471..9459b0fe 100644 --- a/bookwyrm/templates/snippets/authors.html +++ b/bookwyrm/templates/snippets/authors.html @@ -1 +1,17 @@ -{% for author in book.authors.all %}{{ author.name }}{% if not forloop.last %}, {% endif %}{% endfor %} +{% spaceless %} +{% comment %} + @todo The author property needs to be an Organization or a Person. We’ll be using Thing which is the more generic ancestor. + @see https://schema.org/Author +{% endcomment %} +{% for author in book.authors.all %} + {% if not forloop.last %}, {% endif %} +{% endfor %} +{% endspaceless %} diff --git a/bookwyrm/templates/snippets/book_cover.html b/bookwyrm/templates/snippets/book_cover.html index 0dbc3672..ce47819e 100644 --- a/bookwyrm/templates/snippets/book_cover.html +++ b/bookwyrm/templates/snippets/book_cover.html @@ -1,13 +1,29 @@ +{% spaceless %} + {% load bookwyrm_tags %} +{% load i18n %} +
-{% if book.cover %} -{{ book.alt_text }} -{% else %} -
- No cover -
-

{{ book.alt_text }}

+ {% if book.cover %} + {{ book.alt_text }} + {% else %} +
+ {% trans + +
+

{{ book.alt_text }}

+
-
-{% endif %} + {% endif %}
+{% endspaceless %} diff --git a/bookwyrm/templates/snippets/status/status_content.html b/bookwyrm/templates/snippets/status/status_content.html index 43cdc5d2..499c31ad 100644 --- a/bookwyrm/templates/snippets/status/status_content.html +++ b/bookwyrm/templates/snippets/status/status_content.html @@ -1,68 +1,137 @@ +{% spaceless %} + {% load bookwyrm_tags %} {% load i18n %} -
- {% if status.status_type == 'Review' or status.status_type == 'Rating' %} -
- {% if status.name %} -

- {{ status.name|escape }} -

- {% endif %} - {% include 'snippets/stars.html' with rating=status.rating %} -
+ +{% with status_type=status.status_type %} +
+ {% if status_type == 'Review' or status_type == 'Rating' %} +
+ {% if status.name %} +

+ {{ status.name|escape }} +

+ {% endif %} + + + + + {% if status_type == 'Rating' %} + {# @todo Is it possible to not hard-code the value? #} + + {% endif %} + + + {% include 'snippets/stars.html' with rating=status.rating %} +
{% endif %} {% if status.content_warning %} -
-

{{ status.content_warning }}

- {% trans "Show more" as button_text %} - {% include 'snippets/toggle/open_button.html' with text=button_text class="is-small" controls_text="show-status-cw" controls_uid=status.id %} -
+
+

{{ status.content_warning }}

+ + {% trans "Show more" as button_text %} + + {% with text=button_text class="is-small" controls_text="show-status-cw" controls_uid=status.id %} + {% include 'snippets/toggle/open_button.html' %} + {% endwith %} +
{% endif %} -