diff --git a/.env.example b/.env.example
index 2000a716..ca6f65bb 100644
--- a/.env.example
+++ b/.env.example
@@ -8,6 +8,8 @@ USE_HTTPS=true
DOMAIN=your.domain.here
EMAIL=your@email.here
+# Instance defualt language (see options at bookwyrm/settings.py "LANGUAGES"
+LANGUAGE_CODE="en-us"
# Used for deciding which editions to prefer
DEFAULT_LANGUAGE="English"
diff --git a/bookwyrm/forms.py b/bookwyrm/forms.py
index ef9bbc15..e442dbf4 100644
--- a/bookwyrm/forms.py
+++ b/bookwyrm/forms.py
@@ -444,6 +444,12 @@ class ListForm(CustomForm):
fields = ["user", "name", "description", "curation", "privacy", "group"]
+class ListItemForm(CustomForm):
+ class Meta:
+ model = models.ListItem
+ fields = ["user", "book", "book_list", "notes"]
+
+
class GroupForm(CustomForm):
class Meta:
model = models.Group
diff --git a/bookwyrm/management/commands/initdb.py b/bookwyrm/management/commands/initdb.py
index 37dd66af..09d86462 100644
--- a/bookwyrm/management/commands/initdb.py
+++ b/bookwyrm/management/commands/initdb.py
@@ -19,9 +19,7 @@ def init_permissions():
{
"codename": "edit_instance_settings",
"name": "change the instance info",
- "groups": [
- "admin",
- ],
+ "groups": ["admin"],
},
{
"codename": "set_user_group",
@@ -55,7 +53,7 @@ def init_permissions():
},
]
- content_type = models.ContentType.objects.get_for_model(User)
+ content_type = ContentType.objects.get_for_model(models.User)
for permission in permissions:
permission_obj = Permission.objects.create(
codename=permission["codename"],
@@ -66,15 +64,12 @@ def init_permissions():
for group_name in permission["groups"]:
Group.objects.get(name=group_name).permissions.add(permission_obj)
- # while the groups and permissions shouldn't be changed because the code
- # depends on them, what permissions go with what groups should be editable
-
def init_connectors():
"""access book data sources"""
models.Connector.objects.create(
identifier="bookwyrm.social",
- name="BookWyrm dot Social",
+ name="Bookwyrm.social",
connector_file="bookwyrm_connector",
base_url="https://bookwyrm.social",
books_url="https://bookwyrm.social/book",
@@ -84,6 +79,7 @@ def init_connectors():
priority=2,
)
+ # pylint: disable=line-too-long
models.Connector.objects.create(
identifier="inventaire.io",
name="Inventaire",
@@ -127,7 +123,7 @@ def init_settings():
)
-def init_link_domains(*_):
+def init_link_domains():
"""safe book links"""
domains = [
("standardebooks.org", "Standard EBooks"),
@@ -144,10 +140,15 @@ def init_link_domains(*_):
)
+# pylint: disable=no-self-use
+# pylint: disable=unused-argument
class Command(BaseCommand):
+ """command-line options"""
+
help = "Initializes the database with starter data"
def add_arguments(self, parser):
+ """specify which function to run"""
parser.add_argument(
"--limit",
default=None,
@@ -155,6 +156,7 @@ class Command(BaseCommand):
)
def handle(self, *args, **options):
+ """execute init"""
limit = options.get("limit")
tables = [
"group",
@@ -164,7 +166,7 @@ class Command(BaseCommand):
"settings",
"linkdomain",
]
- if limit not in tables:
+ if limit and limit not in tables:
raise Exception("Invalid table limit:", limit)
if not limit or limit == "group":
diff --git a/bookwyrm/migrations/0130_alter_listitem_notes.py b/bookwyrm/migrations/0130_alter_listitem_notes.py
new file mode 100644
index 00000000..a12efd40
--- /dev/null
+++ b/bookwyrm/migrations/0130_alter_listitem_notes.py
@@ -0,0 +1,21 @@
+# Generated by Django 3.2.10 on 2022-01-24 20:01
+
+import bookwyrm.models.fields
+from django.db import migrations
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ("bookwyrm", "0129_auto_20220117_1716"),
+ ]
+
+ operations = [
+ migrations.AlterField(
+ model_name="listitem",
+ name="notes",
+ field=bookwyrm.models.fields.TextField(
+ blank=True, max_length=300, null=True
+ ),
+ ),
+ ]
diff --git a/bookwyrm/migrations/0130_alter_user_preferred_language.py b/bookwyrm/migrations/0130_alter_user_preferred_language.py
new file mode 100644
index 00000000..cd5a07ea
--- /dev/null
+++ b/bookwyrm/migrations/0130_alter_user_preferred_language.py
@@ -0,0 +1,37 @@
+# Generated by Django 3.2.10 on 2022-01-24 17:32
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ("bookwyrm", "0129_auto_20220117_1716"),
+ ]
+
+ operations = [
+ migrations.AlterField(
+ model_name="user",
+ name="preferred_language",
+ field=models.CharField(
+ blank=True,
+ choices=[
+ ("en-us", "English"),
+ ("de-de", "Deutsch (German)"),
+ ("es-es", "Español (Spanish)"),
+ ("gl-es", "Galego (Galician)"),
+ ("it-it", "Italiano (Italian)"),
+ ("fr-fr", "Français (French)"),
+ ("lt-lt", "Lietuvių (Lithuanian)"),
+ ("no-no", "Norsk (Norwegian)"),
+ ("pt-br", "Português do Brasil (Brazilian Portuguese)"),
+ ("pt-pt", "Português Europeu (European Portuguese)"),
+ ("sv-se", "Swedish (Svenska)"),
+ ("zh-hans", "简体中文 (Simplified Chinese)"),
+ ("zh-hant", "繁體中文 (Traditional Chinese)"),
+ ],
+ max_length=255,
+ null=True,
+ ),
+ ),
+ ]
diff --git a/bookwyrm/migrations/0131_merge_20220125_1644.py b/bookwyrm/migrations/0131_merge_20220125_1644.py
new file mode 100644
index 00000000..954ddacc
--- /dev/null
+++ b/bookwyrm/migrations/0131_merge_20220125_1644.py
@@ -0,0 +1,13 @@
+# Generated by Django 3.2.10 on 2022-01-25 16:44
+
+from django.db import migrations
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ("bookwyrm", "0130_alter_listitem_notes"),
+ ("bookwyrm", "0130_alter_user_preferred_language"),
+ ]
+
+ operations = []
diff --git a/bookwyrm/models/list.py b/bookwyrm/models/list.py
index d159bc4a..7dff7214 100644
--- a/bookwyrm/models/list.py
+++ b/bookwyrm/models/list.py
@@ -2,6 +2,7 @@
import uuid
from django.apps import apps
+from django.core.exceptions import PermissionDenied
from django.db import models
from django.db.models import Q
from django.utils import timezone
@@ -74,6 +75,22 @@ class List(OrderedCollectionMixin, BookWyrmModel):
return
super().raise_not_editable(viewer)
+ def raise_not_submittable(self, viewer):
+ """can the user submit a book to the list?"""
+ # if you can't view the list you can't submit to it
+ self.raise_visible_to_user(viewer)
+
+ # all good if you're the owner or the list is open
+ if self.user == viewer or self.curation in ["open", "curated"]:
+ return
+ if self.curation == "group":
+ is_group_member = GroupMember.objects.filter(
+ group=self.group, user=viewer
+ ).exists()
+ if is_group_member:
+ return
+ raise PermissionDenied()
+
@classmethod
def followers_filter(cls, queryset, viewer):
"""Override filter for "followers" privacy level to allow non-following
@@ -125,7 +142,7 @@ class ListItem(CollectionItemMixin, BookWyrmModel):
user = fields.ForeignKey(
"User", on_delete=models.PROTECT, activitypub_field="actor"
)
- notes = fields.TextField(blank=True, null=True)
+ notes = fields.TextField(blank=True, null=True, max_length=300)
approved = models.BooleanField(default=True)
order = fields.IntegerField()
endorsement = models.ManyToManyField("User", related_name="endorsers")
diff --git a/bookwyrm/models/site.py b/bookwyrm/models/site.py
index 5d91553e..b2119e23 100644
--- a/bookwyrm/models/site.py
+++ b/bookwyrm/models/site.py
@@ -90,6 +90,14 @@ class SiteSettings(models.Model):
return get_absolute_url(uploaded)
return urljoin(STATIC_FULL_URL, default_path)
+ def save(self, *args, **kwargs):
+ """if require_confirm_email is disabled, make sure no users are pending"""
+ if not self.require_confirm_email:
+ User.objects.filter(is_active=False, deactivation_reason="pending").update(
+ is_active=True, deactivation_reason=None
+ )
+ super().save(*args, **kwargs)
+
class SiteInvite(models.Model):
"""gives someone access to create an account on the instance"""
diff --git a/bookwyrm/settings.py b/bookwyrm/settings.py
index 9f836278..282a0de3 100644
--- a/bookwyrm/settings.py
+++ b/bookwyrm/settings.py
@@ -14,7 +14,7 @@ VERSION = "0.2.0"
PAGE_LENGTH = env("PAGE_LENGTH", 15)
DEFAULT_LANGUAGE = env("DEFAULT_LANGUAGE", "English")
-JS_CACHE = "76c5ff1f"
+JS_CACHE = "7b5303af"
# email
EMAIL_BACKEND = env("EMAIL_BACKEND", "django.core.mail.backends.smtp.EmailBackend")
@@ -245,7 +245,7 @@ AUTH_PASSWORD_VALIDATORS = [
# Internationalization
# https://docs.djangoproject.com/en/3.2/topics/i18n/
-LANGUAGE_CODE = "en-us"
+LANGUAGE_CODE = env("LANGUAGE_CODE", "en-us")
LANGUAGES = [
("en-us", _("English")),
("de-de", _("Deutsch (German)")),
@@ -257,6 +257,7 @@ LANGUAGES = [
("no-no", _("Norsk (Norwegian)")),
("pt-br", _("Português do Brasil (Brazilian Portuguese)")),
("pt-pt", _("Português Europeu (European Portuguese)")),
+ ("sv-se", _("Swedish (Svenska)")),
("zh-hans", _("简体中文 (Simplified Chinese)")),
("zh-hant", _("繁體中文 (Traditional Chinese)")),
]
diff --git a/bookwyrm/static/js/bookwyrm.js b/bookwyrm/static/js/bookwyrm.js
index 94163787..cf3ce303 100644
--- a/bookwyrm/static/js/bookwyrm.js
+++ b/bookwyrm/static/js/bookwyrm.js
@@ -122,39 +122,13 @@ let BookWyrm = new (class {
*/
updateCountElement(counter, data) {
let count = data.count;
- const count_by_type = data.count_by_type;
+
+ if (count === undefined) {
+ return;
+ }
+
const currentCount = counter.innerText;
const hasMentions = data.has_mentions;
- const allowedStatusTypesEl = document.getElementById("unread-notifications-wrapper");
-
- // If we're on the right counter element
- if (counter.closest("[data-poll-wrapper]").contains(allowedStatusTypesEl)) {
- const allowedStatusTypes = JSON.parse(allowedStatusTypesEl.textContent);
-
- // For keys in common between allowedStatusTypes and count_by_type
- // This concerns 'review', 'quotation', 'comment'
- count = allowedStatusTypes.reduce(function (prev, currentKey) {
- const currentValue = count_by_type[currentKey] | 0;
-
- return prev + currentValue;
- }, 0);
-
- // Add all the "other" in count_by_type if 'everything' is allowed
- if (allowedStatusTypes.includes("everything")) {
- // Clone count_by_type with 0 for reviews/quotations/comments
- const count_by_everything_else = Object.assign({}, count_by_type, {
- review: 0,
- quotation: 0,
- comment: 0,
- });
-
- count = Object.keys(count_by_everything_else).reduce(function (prev, currentKey) {
- const currentValue = count_by_everything_else[currentKey] | 0;
-
- return prev + currentValue;
- }, count);
- }
- }
if (count != currentCount) {
this.addRemoveClass(counter.closest("[data-poll-wrapper]"), "is-hidden", count < 1);
@@ -517,7 +491,7 @@ let BookWyrm = new (class {
duplicateInput(event) {
const trigger = event.currentTarget;
- const input_id = trigger.dataset["duplicate"];
+ const input_id = trigger.dataset.duplicate;
const orig = document.getElementById(input_id);
const parent = orig.parentNode;
const new_count = parent.querySelectorAll("input").length + 1;
diff --git a/bookwyrm/templates/about/about.html b/bookwyrm/templates/about/about.html
index acc89b0e..4e533b11 100644
--- a/bookwyrm/templates/about/about.html
+++ b/bookwyrm/templates/about/about.html
@@ -12,6 +12,7 @@
{% block about_content %}
{# seven day cache #}
{% cache 604800 about_page %}
+
{% get_book_superlatives as superlatives %}
@@ -26,7 +27,7 @@