Tag version 0.7.0.
-----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEEHCg/i5LQ+bsUm3NgpDqESxFPmwgFAmUz+08ACgkQpDqESxFP mwgs3w/7BgDnbP68IKA6r59JqWGIYmtSdP+U092b7tyrKWsK/RbEfuUowt6qx2+I p2BHmWNOToueMHr8nWwWEVyZvXfuFxFV03a3WXD6ifCss0zPZVRVfpENPptxqyxy 1A8dVveycM8Bv3ZcemMsHsx2ocPqdeBFB+TjHespq2RFg8miWK4D3+UpgguorCa0 qiS8R0ZQERRIWZnnKxgaJ+Sme+2aMbF/lUslL+1dnTeHrEMVGpmBiKXELV6TYYE2 Tmw8gSZKpe9K98e3NN1K94TGEruAJuZtGc8ekxRMaEXRDMvjasK1Nznz4FUNHsbM ExwDY1+7FEA5D3T/PIlhtAdf6szeHvRs1mIoEbtLw3T+OIIfNugkqnUz0Xv5Bz9+ kKoWxxFmvYNHZxEggTQT4ik0ufaMuEHMQofYtKHJPqzottgS0cdV+cusda87hZ95 3+0RH8vJYzYk1iPlkdtct5p6f9mMljF9T91PcHrbb9GgOI8NKBmHyQWtpIDB00lT MQEhbtz2VUy572JB3w8vXXPb79L700Obrw7DZXk/K4c0ULM27fZX+PCbXKKITR5H vnsrhQcVT4FP46nRDAz0COWVdAsC7SrLPhoq9WmWR4WVea/PpvIsODURLdmmsGIy lqj2WnF6LiY965JLvCtbuyDO2wNMXjv24j+22aPmZ12wgwe14N8= =vWVR -----END PGP SIGNATURE----- Merge tag 'v0.7.0' into nix
This commit is contained in:
commit
23c8ffeae9
48 changed files with 820 additions and 552 deletions
1
.prettierrc
Normal file
1
.prettierrc
Normal file
|
@ -0,0 +1 @@
|
|||
'trailingComma': 'es5'
|
1
VERSION
Normal file
1
VERSION
Normal file
|
@ -0,0 +1 @@
|
|||
0.6.6
|
|
@ -201,14 +201,13 @@ class Book(BookDataModel):
|
|||
@property
|
||||
def alt_text(self):
|
||||
"""image alt test"""
|
||||
text = self.title
|
||||
if self.edition_info:
|
||||
text += f" ({self.edition_info})"
|
||||
return text
|
||||
author = f"{name}: " if (name := self.author_text) else ""
|
||||
edition = f" ({info})" if (info := self.edition_info) else ""
|
||||
return f"{author}{self.title}{edition}"
|
||||
|
||||
def save(self, *args: Any, **kwargs: Any) -> None:
|
||||
"""can't be abstract for query reasons, but you shouldn't USE it"""
|
||||
if not isinstance(self, Edition) and not isinstance(self, Work):
|
||||
if not isinstance(self, (Edition, Work)):
|
||||
raise ValueError("Books should be added as Editions or Works")
|
||||
|
||||
return super().save(*args, **kwargs)
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
""" activitypub-aware django model fields """
|
||||
from dataclasses import MISSING
|
||||
from datetime import datetime
|
||||
import re
|
||||
from uuid import uuid4
|
||||
from urllib.parse import urljoin
|
||||
|
@ -534,8 +535,10 @@ class DateTimeField(ActivitypubFieldMixin, models.DateTimeField):
|
|||
return value.isoformat()
|
||||
|
||||
def field_from_activity(self, value, allow_external_connections=True):
|
||||
missing_fields = datetime(1970, 1, 1) # "2022-10" => "2022-10-01"
|
||||
try:
|
||||
date_value = dateutil.parser.parse(value)
|
||||
# TODO(dato): investigate `ignoretz=True` wrt bookwyrm#3028.
|
||||
date_value = dateutil.parser.parse(value, default=missing_fields)
|
||||
try:
|
||||
return timezone.make_aware(date_value)
|
||||
except ValueError:
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
""" track progress of goodreads imports """
|
||||
from datetime import datetime
|
||||
import math
|
||||
import re
|
||||
import dateutil.parser
|
||||
|
@ -259,38 +260,30 @@ class ImportItem(models.Model):
|
|||
except ValueError:
|
||||
return None
|
||||
|
||||
def _parse_datefield(self, field, /):
|
||||
if not (date := self.normalized_data.get(field)):
|
||||
return None
|
||||
|
||||
defaults = datetime(1970, 1, 1) # "2022-10" => "2022-10-01"
|
||||
parsed = dateutil.parser.parse(date, default=defaults)
|
||||
|
||||
# Keep timezone if import already had one, else use default.
|
||||
return parsed if timezone.is_aware(parsed) else timezone.make_aware(parsed)
|
||||
|
||||
@property
|
||||
def date_added(self):
|
||||
"""when the book was added to this dataset"""
|
||||
if self.normalized_data.get("date_added"):
|
||||
parsed_date_added = dateutil.parser.parse(
|
||||
self.normalized_data.get("date_added")
|
||||
)
|
||||
|
||||
if timezone.is_aware(parsed_date_added):
|
||||
# Keep timezone if import already had one
|
||||
return parsed_date_added
|
||||
|
||||
return timezone.make_aware(parsed_date_added)
|
||||
return None
|
||||
return self._parse_datefield("date_added")
|
||||
|
||||
@property
|
||||
def date_started(self):
|
||||
"""when the book was started"""
|
||||
if self.normalized_data.get("date_started"):
|
||||
return timezone.make_aware(
|
||||
dateutil.parser.parse(self.normalized_data.get("date_started"))
|
||||
)
|
||||
return None
|
||||
return self._parse_datefield("date_started")
|
||||
|
||||
@property
|
||||
def date_read(self):
|
||||
"""the date a book was completed"""
|
||||
if self.normalized_data.get("date_finished"):
|
||||
return timezone.make_aware(
|
||||
dateutil.parser.parse(self.normalized_data.get("date_finished"))
|
||||
)
|
||||
return None
|
||||
return self._parse_datefield("date_finished")
|
||||
|
||||
@property
|
||||
def reads(self):
|
||||
|
|
|
@ -366,7 +366,8 @@ class Quotation(BookStatus):
|
|||
quote = re.sub(r"^<p>", '<p>"', self.quote)
|
||||
quote = re.sub(r"</p>$", '"</p>', quote)
|
||||
title, href = self.book.title, self.book.remote_id
|
||||
citation = f'— <a href="{href}"><i>{title}</i></a>'
|
||||
author = f"{name}: " if (name := self.book.author_text) else ""
|
||||
citation = f'— {author}<a href="{href}"><i>{title}</i></a>'
|
||||
if position := self._format_position():
|
||||
citation += f", {position}"
|
||||
return f"{quote} <p>{citation}</p>{self.content}"
|
||||
|
|
|
@ -4,6 +4,7 @@ from typing import AnyStr
|
|||
|
||||
from environs import Env
|
||||
|
||||
|
||||
import requests
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from django.core.exceptions import ImproperlyConfigured
|
||||
|
@ -14,7 +15,13 @@ from django.core.exceptions import ImproperlyConfigured
|
|||
env = Env()
|
||||
env.read_env()
|
||||
DOMAIN = env("DOMAIN")
|
||||
VERSION = "0.6.6"
|
||||
|
||||
with open("VERSION", encoding="utf-8") as f:
|
||||
version = f.read()
|
||||
version = version.replace("\n", "")
|
||||
f.close()
|
||||
|
||||
VERSION = version
|
||||
|
||||
RELEASE_API = env(
|
||||
"RELEASE_API",
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
@charset "utf-8";
|
||||
|
||||
@import "vendor/bulma/bulma.sass";
|
||||
@import "bookwyrm/all.scss";
|
||||
@import "vendor/bulma/bulma";
|
||||
@import "bookwyrm/all";
|
||||
|
|
|
@ -16,9 +16,7 @@
|
|||
@import "components/status";
|
||||
@import "components/tabs";
|
||||
@import "components/toggle";
|
||||
|
||||
@import "overrides/bulma_overrides";
|
||||
|
||||
@import "utilities/a11y";
|
||||
@import "utilities/alignments";
|
||||
@import "utilities/colors";
|
||||
|
@ -40,10 +38,12 @@ body {
|
|||
width: 12px;
|
||||
height: 12px;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-thumb {
|
||||
background: $scrollbar-thumb;
|
||||
border-radius: 0.5em;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-track {
|
||||
background: $scrollbar-track;
|
||||
}
|
||||
|
@ -89,7 +89,6 @@ button::-moz-focus-inner {
|
|||
/** Utilities not covered by Bulma
|
||||
******************************************************************************/
|
||||
|
||||
|
||||
.tag.is-small {
|
||||
height: auto;
|
||||
}
|
||||
|
@ -144,7 +143,6 @@ button.button-paragraph {
|
|||
vertical-align: middle;
|
||||
}
|
||||
|
||||
|
||||
/** States
|
||||
******************************************************************************/
|
||||
|
||||
|
@ -159,7 +157,6 @@ button.button-paragraph {
|
|||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
|
||||
/* Notifications page
|
||||
******************************************************************************/
|
||||
|
||||
|
|
|
@ -43,7 +43,7 @@
|
|||
max-height: 100%;
|
||||
|
||||
/* Useful when stretching under-sized images. */
|
||||
image-rendering: optimizeQuality;
|
||||
image-rendering: optimizequality;
|
||||
image-rendering: smooth;
|
||||
}
|
||||
|
||||
|
|
|
@ -30,20 +30,20 @@
|
|||
}
|
||||
|
||||
.copy-tooltip {
|
||||
overflow: visible;
|
||||
visibility: hidden;
|
||||
width: 140px;
|
||||
background-color: #555;
|
||||
color: #fff;
|
||||
text-align: center;
|
||||
border-radius: 6px;
|
||||
padding: 5px;
|
||||
position: absolute;
|
||||
z-index: 1;
|
||||
margin-left: -30px;
|
||||
margin-top: -45px;
|
||||
opacity: 0;
|
||||
transition: opacity 0.3s;
|
||||
overflow: visible;
|
||||
visibility: hidden;
|
||||
width: 140px;
|
||||
background-color: #555;
|
||||
color: #fff;
|
||||
text-align: center;
|
||||
border-radius: 6px;
|
||||
padding: 5px;
|
||||
position: absolute;
|
||||
z-index: 1;
|
||||
margin-left: -30px;
|
||||
margin-top: -45px;
|
||||
opacity: 0;
|
||||
transition: opacity 0.3s;
|
||||
}
|
||||
|
||||
.copy-tooltip::after {
|
||||
|
@ -54,5 +54,5 @@
|
|||
margin-left: -60px;
|
||||
border-width: 5px;
|
||||
border-style: solid;
|
||||
border-color: #555 transparent transparent transparent;
|
||||
}
|
||||
border-color: #555 transparent transparent;
|
||||
}
|
||||
|
|
|
@ -44,12 +44,12 @@
|
|||
|
||||
.bw-tabs a:hover {
|
||||
border-bottom-color: transparent;
|
||||
color: $text
|
||||
color: $text;
|
||||
}
|
||||
|
||||
.bw-tabs a.is-active {
|
||||
border-bottom-color: transparent;
|
||||
color: $link
|
||||
color: $link;
|
||||
}
|
||||
|
||||
.bw-tabs.is-left {
|
||||
|
|
Binary file not shown.
|
@ -43,6 +43,8 @@
|
|||
<glyph unicode="" glyph-name="barcode" d="M0 832h128v-640h-128zM192 832h64v-640h-64zM320 832h64v-640h-64zM512 832h64v-640h-64zM768 832h64v-640h-64zM960 832h64v-640h-64zM640 832h32v-640h-32zM448 832h32v-640h-32zM864 832h32v-640h-32zM0 128h64v-64h-64zM192 128h64v-64h-64zM320 128h64v-64h-64zM640 128h64v-64h-64zM960 128h64v-64h-64zM768 128h128v-64h-128zM448 128h128v-64h-128z" />
|
||||
<glyph unicode="" glyph-name="spinner" d="M384 832c0 70.692 57.308 128 128 128s128-57.308 128-128c0-70.692-57.308-128-128-128s-128 57.308-128 128zM655.53 719.53c0 70.692 57.308 128 128 128s128-57.308 128-128c0-70.692-57.308-128-128-128s-128 57.308-128 128zM832 448c0 35.346 28.654 64 64 64s64-28.654 64-64c0-35.346-28.654-64-64-64s-64 28.654-64 64zM719.53 176.47c0 35.346 28.654 64 64 64s64-28.654 64-64c0-35.346-28.654-64-64-64s-64 28.654-64 64zM448.002 64c0 0 0 0 0 0 0 35.346 28.654 64 64 64s64-28.654 64-64c0 0 0 0 0 0 0-35.346-28.654-64-64-64s-64 28.654-64 64zM176.472 176.47c0 0 0 0 0 0 0 35.346 28.654 64 64 64s64-28.654 64-64c0 0 0 0 0 0 0-35.346-28.654-64-64-64s-64 28.654-64 64zM144.472 719.53c0 0 0 0 0 0 0 53.019 42.981 96 96 96s96-42.981 96-96c0 0 0 0 0 0 0-53.019-42.981-96-96-96s-96 42.981-96 96zM56 448c0 39.765 32.235 72 72 72s72-32.235 72-72c0-39.765-32.235-72-72-72s-72 32.235-72 72z" />
|
||||
<glyph unicode="" glyph-name="search" d="M992.262 88.604l-242.552 206.294c-25.074 22.566-51.89 32.926-73.552 31.926 57.256 67.068 91.842 154.078 91.842 249.176 0 212.078-171.922 384-384 384-212.076 0-384-171.922-384-384s171.922-384 384-384c95.098 0 182.108 34.586 249.176 91.844-1-21.662 9.36-48.478 31.926-73.552l206.294-242.552c35.322-39.246 93.022-42.554 128.22-7.356s31.892 92.898-7.354 128.22zM384 320c-141.384 0-256 114.616-256 256s114.616 256 256 256 256-114.616 256-256-114.614-256-256-256z" />
|
||||
<glyph unicode="" glyph-name="eye" d="M512 768c-223.318 0-416.882-130.042-512-320 95.118-189.958 288.682-320 512-320 223.312 0 416.876 130.042 512 320-95.116 189.958-288.688 320-512 320zM764.45 598.296c60.162-38.374 111.142-89.774 149.434-150.296-38.292-60.522-89.274-111.922-149.436-150.296-75.594-48.218-162.89-73.704-252.448-73.704-89.56 0-176.858 25.486-252.452 73.704-60.158 38.372-111.138 89.772-149.432 150.296 38.292 60.524 89.274 111.924 149.434 150.296 3.918 2.5 7.876 4.922 11.86 7.3-9.96-27.328-15.41-56.822-15.41-87.596 0-141.382 114.616-256 256-256 141.382 0 256 114.618 256 256 0 30.774-5.452 60.268-15.408 87.598 3.978-2.378 7.938-4.802 11.858-7.302v0zM512 544c0-53.020-42.98-96-96-96s-96 42.98-96 96 42.98 96 96 96 96-42.982 96-96z" />
|
||||
<glyph unicode="" glyph-name="eye-blocked" d="M945.942 945.942c-18.746 18.744-49.136 18.744-67.882 0l-202.164-202.164c-51.938 15.754-106.948 24.222-163.896 24.222-223.318 0-416.882-130.042-512-320 41.122-82.124 100.648-153.040 173.022-207.096l-158.962-158.962c-18.746-18.746-18.746-49.136 0-67.882 9.372-9.374 21.656-14.060 33.94-14.060s24.568 4.686 33.942 14.058l864 864c18.744 18.746 18.744 49.138 0 67.884zM416 640c42.24 0 78.082-27.294 90.92-65.196l-121.724-121.724c-37.902 12.838-65.196 48.68-65.196 90.92 0 53.020 42.98 96 96 96zM110.116 448c38.292 60.524 89.274 111.924 149.434 150.296 3.918 2.5 7.876 4.922 11.862 7.3-9.962-27.328-15.412-56.822-15.412-87.596 0-54.89 17.286-105.738 46.7-147.418l-60.924-60.924c-52.446 36.842-97.202 83.882-131.66 138.342zM768 518c0 27.166-4.256 53.334-12.102 77.898l-321.808-321.808c24.568-7.842 50.742-12.090 77.91-12.090 141.382 0 256 114.618 256 256zM830.026 670.026l-69.362-69.362c1.264-0.786 2.53-1.568 3.786-2.368 60.162-38.374 111.142-89.774 149.434-150.296-38.292-60.522-89.274-111.922-149.436-150.296-75.594-48.218-162.89-73.704-252.448-73.704-38.664 0-76.902 4.76-113.962 14.040l-76.894-76.894c59.718-21.462 123.95-33.146 190.856-33.146 223.31 0 416.876 130.042 512 320-45.022 89.916-112.118 166.396-193.974 222.026z" />
|
||||
<glyph unicode="" glyph-name="star-empty" d="M1024 562.95l-353.78 51.408-158.22 320.582-158.216-320.582-353.784-51.408 256-249.538-60.432-352.352 316.432 166.358 316.432-166.358-60.434 352.352 256.002 249.538zM512 206.502l-223.462-117.48 42.676 248.83-180.786 176.222 249.84 36.304 111.732 226.396 111.736-226.396 249.836-36.304-180.788-176.222 42.678-248.83-223.462 117.48z" />
|
||||
<glyph unicode="" glyph-name="star-half" d="M1024 562.95l-353.78 51.408-158.22 320.582-158.216-320.582-353.784-51.408 256-249.538-60.432-352.352 316.432 166.358 316.432-166.358-60.434 352.352 256.002 249.538zM512 206.502l-0.942-0.496 0.942 570.768 111.736-226.396 249.836-36.304-180.788-176.222 42.678-248.83-223.462 117.48z" />
|
||||
<glyph unicode="" glyph-name="star-full" d="M1024 562.95l-353.78 51.408-158.22 320.582-158.216-320.582-353.784-51.408 256-249.538-60.432-352.352 316.432 166.358 316.432-166.358-60.434 352.352 256.002 249.538z" />
|
||||
|
|
Before Width: | Height: | Size: 34 KiB After Width: | Height: | Size: 36 KiB |
Binary file not shown.
Binary file not shown.
|
@ -1,4 +1,4 @@
|
|||
@import "../vendor/bulma/sass/utilities/initial-variables.sass";
|
||||
@import "../vendor/bulma/sass/utilities/initial-variables";
|
||||
|
||||
/* Colors
|
||||
******************************************************************************/
|
||||
|
@ -16,7 +16,7 @@ $danger-light: #481922;
|
|||
$light: #393939;
|
||||
$red: #ffa1b4;
|
||||
$black: #000;
|
||||
$white-ter: hsl(0, 0%, 90%);
|
||||
$white-ter: hsl(0deg, 0%, 90%);
|
||||
|
||||
/* book cover standins */
|
||||
$no-cover-color: #002549;
|
||||
|
@ -79,7 +79,7 @@ $info-dark: #72b6ee;
|
|||
}
|
||||
|
||||
/* misc */
|
||||
$shadow: 0 0.5em 0.5em -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 0 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;
|
||||
|
@ -97,27 +97,23 @@ $family-secondary: $family-sans-serif;
|
|||
color: $grey-light !important;
|
||||
}
|
||||
|
||||
|
||||
.tabs li:not(.is-active) a {
|
||||
color: #2e7eb9 !important;
|
||||
}
|
||||
.tabs li:not(.is-active) a:hover {
|
||||
|
||||
.tabs li:not(.is-active) a:hover {
|
||||
border-bottom-color: #2e7eb9 !important;
|
||||
}
|
||||
|
||||
.tabs li:not(.is-active) a {
|
||||
color: #2e7eb9 !important;
|
||||
}
|
||||
|
||||
.tabs li.is-active a {
|
||||
color: #e6e6e6 !important;
|
||||
border-bottom-color: #e6e6e6 !important ;
|
||||
border-bottom-color: #e6e6e6 !important;
|
||||
}
|
||||
|
||||
|
||||
#qrcode svg {
|
||||
background-color: #a6a6a6;
|
||||
}
|
||||
|
||||
@import "../bookwyrm.scss";
|
||||
@import "../bookwyrm";
|
||||
@import "../vendor/icons.css";
|
||||
@import "../vendor/shepherd.scss";
|
||||
@import "../vendor/shepherd";
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
@import "../vendor/bulma/sass/utilities/derived-variables.sass";
|
||||
@import "../vendor/bulma/sass/utilities/derived-variables";
|
||||
|
||||
/* Colors
|
||||
******************************************************************************/
|
||||
|
@ -68,19 +68,16 @@ $family-secondary: $family-sans-serif;
|
|||
.tabs li:not(.is-active) a {
|
||||
color: #3273dc !important;
|
||||
}
|
||||
.tabs li:not(.is-active) a:hover {
|
||||
border-bottom-color: #3273dc !important;
|
||||
}
|
||||
|
||||
.tabs li:not(.is-active) a {
|
||||
color: #3273dc !important;
|
||||
.tabs li:not(.is-active) a:hover {
|
||||
border-bottom-color: #3273dc !important;
|
||||
}
|
||||
|
||||
.tabs li.is-active a {
|
||||
color: #4a4a4a !important;
|
||||
border-bottom-color: #4a4a4a !important ;
|
||||
border-bottom-color: #4a4a4a !important;
|
||||
}
|
||||
|
||||
|
||||
@import "../bookwyrm.scss";
|
||||
@import "../bookwyrm";
|
||||
@import "../vendor/icons.css";
|
||||
@import "../vendor/shepherd.scss";
|
||||
@import "../vendor/shepherd";
|
||||
|
|
6
bookwyrm/static/css/vendor/icons.css
vendored
6
bookwyrm/static/css/vendor/icons.css
vendored
|
@ -155,3 +155,9 @@
|
|||
.icon-barcode:before {
|
||||
content: "\e937";
|
||||
}
|
||||
.icon-eye:before {
|
||||
content: "\e9ce";
|
||||
}
|
||||
.icon-eye-blocked:before {
|
||||
content: "\e9d1";
|
||||
}
|
||||
|
|
|
@ -30,6 +30,12 @@ let BookWyrm = new (class {
|
|||
.querySelectorAll("[data-back]")
|
||||
.forEach((button) => button.addEventListener("click", this.back));
|
||||
|
||||
document
|
||||
.querySelectorAll("[data-password-icon]")
|
||||
.forEach((button) =>
|
||||
button.addEventListener("click", this.togglePasswordVisibility.bind(this))
|
||||
);
|
||||
|
||||
document
|
||||
.querySelectorAll('input[type="file"]')
|
||||
.forEach((node) => node.addEventListener("change", this.disableIfTooLarge.bind(this)));
|
||||
|
@ -820,4 +826,24 @@ let BookWyrm = new (class {
|
|||
|
||||
form.querySelector('input[name="preferred_timezone"]').value = tz;
|
||||
}
|
||||
|
||||
togglePasswordVisibility(event) {
|
||||
const iconElement = event.currentTarget.getElementsByTagName("button")[0];
|
||||
const passwordElementId = event.currentTarget.dataset.for;
|
||||
const passwordInputElement = document.getElementById(passwordElementId);
|
||||
|
||||
if (!passwordInputElement) return;
|
||||
|
||||
if (passwordInputElement.type === "password") {
|
||||
passwordInputElement.type = "text";
|
||||
this.addRemoveClass(iconElement, "icon-eye-blocked");
|
||||
this.addRemoveClass(iconElement, "icon-eye", true);
|
||||
} else {
|
||||
passwordInputElement.type = "password";
|
||||
this.addRemoveClass(iconElement, "icon-eye");
|
||||
this.addRemoveClass(iconElement, "icon-eye-blocked", true);
|
||||
}
|
||||
|
||||
this.toggleFocus(passwordElementId);
|
||||
}
|
||||
})();
|
||||
|
|
|
@ -47,12 +47,11 @@
|
|||
.querySelectorAll("[data-remove]")
|
||||
.forEach((node) => node.addEventListener("click", removeInput));
|
||||
|
||||
// Get the element, add a keypress listener...
|
||||
// Get element, add a keypress listener...
|
||||
document.getElementById("subjects").addEventListener("keypress", function (e) {
|
||||
// e.target is the element where it listens!
|
||||
// if e.target is input field within the "subjects" div, do stuff
|
||||
// Linstening to element e.target
|
||||
// If e.target is an input field within "subjects" div preventDefault()
|
||||
if (e.target && e.target.nodeName == "INPUT") {
|
||||
// Item found, prevent default
|
||||
if (event.keyCode == 13) {
|
||||
event.preventDefault();
|
||||
}
|
||||
|
|
|
@ -144,14 +144,6 @@
|
|||
</a>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% if author.isfdb %}
|
||||
<div>
|
||||
<a itemprop="sameAs" href="https://www.isfdb.org/cgi-bin/ea.cgi?{{ author.isfdb }}" target="_blank" rel="nofollow noopener noreferrer">
|
||||
{% trans "View ISFDB entry" %}
|
||||
</a>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</section>
|
||||
{% endif %}
|
||||
|
|
|
@ -44,16 +44,18 @@
|
|||
{% endif %}
|
||||
|
||||
{% if book.series %}
|
||||
<meta itemprop="isPartOf" content="{{ book.series | escape }}">
|
||||
<meta itemprop="volumeNumber" content="{{ book.series_number }}">
|
||||
|
||||
<meta itemprop="position" content="{{ book.series_number }}">
|
||||
<span itemprop="isPartOf" itemscope itemtype="https://schema.org/BookSeries">
|
||||
{% if book.authors.exists %}
|
||||
<a href="{% url 'book-series-by' book.authors.first.id %}?series_name={{ book.series }}">
|
||||
<a href="{% url 'book-series-by' book.authors.first.id %}?series_name={{ book.series | urlencode }}"
|
||||
itemprop="url">
|
||||
{% endif %}
|
||||
{{ book.series }}{% if book.series_number %} #{{ book.series_number }}{% endif %}
|
||||
<span itemprop="name">{{ book.series }}</span>
|
||||
{% if book.series_number %} #{{ book.series_number }}{% endif %}
|
||||
{% if book.authors.exists %}
|
||||
</a>
|
||||
{% endif %}
|
||||
</span>
|
||||
{% endif %}
|
||||
</p>
|
||||
{% endif %}
|
||||
|
@ -186,8 +188,6 @@
|
|||
itemtype="https://schema.org/AggregateRating"
|
||||
>
|
||||
<meta itemprop="ratingValue" content="{{ rating|floatformat }}">
|
||||
{# @todo Is it possible to not hard-code the value? #}
|
||||
<meta itemprop="bestRating" content="5">
|
||||
<meta itemprop="reviewCount" content="{{ review_count }}">
|
||||
|
||||
<span>
|
||||
|
|
|
@ -40,16 +40,13 @@
|
|||
</p>
|
||||
{% endif %}
|
||||
|
||||
{% with date=book.published_date|naturalday publisher=book.publishers|join:', ' %}
|
||||
{% if date or book.first_published_date or book.publishers %}
|
||||
{% if date or book.first_published_date %}
|
||||
{% if book.published_date or book.first_published_date %}
|
||||
<meta
|
||||
itemprop="datePublished"
|
||||
content="{{ book.first_published_date|default:book.published_date|date:'Y-m-d' }}"
|
||||
>
|
||||
{% endif %}
|
||||
<p>
|
||||
|
||||
{% 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
|
||||
|
@ -60,14 +57,14 @@
|
|||
{% endfor %}
|
||||
{% endif %}
|
||||
|
||||
{% if date and publisher %}
|
||||
{% with date=book.published_date|default:book.first_published_date|naturalday publisher=book.publishers|join:', ' %}
|
||||
{% if book.published_date and publisher %}
|
||||
{% blocktrans %}Published {{ date }} by {{ publisher }}.{% endblocktrans %}
|
||||
{% elif date %}
|
||||
{% blocktrans %}Published {{ date }}{% endblocktrans %}
|
||||
{% elif publisher %}
|
||||
{% blocktrans %}Published by {{ publisher }}.{% endblocktrans %}
|
||||
{% elif date %}
|
||||
{% blocktrans %}Published {{ date }}{% endblocktrans %}
|
||||
{% endif %}
|
||||
{% endwith %}
|
||||
</p>
|
||||
{% endif %}
|
||||
{% endwith %}
|
||||
{% endspaceless %}
|
||||
|
|
|
@ -5,13 +5,18 @@
|
|||
{% include 'snippets/avatar.html' with user=user %}
|
||||
</div>
|
||||
|
||||
<div class="media-content">
|
||||
<div>
|
||||
<a href="{{ user.local_path }}">{{ user.display_name }}</a>
|
||||
<div class="media-content" itemprop="review" itemscope itemtype="https://schema.org/Review">
|
||||
<div itemprop="author"
|
||||
itemscope
|
||||
itemtype="https://schema.org/Person"
|
||||
>
|
||||
<a href="{{ user.local_path }}" itemprop="url">
|
||||
<span itemprop="name">{{ user.display_name }}</span>
|
||||
</a>
|
||||
</div>
|
||||
<div class="is-flex">
|
||||
<div class="is-flex" itemprop="reviewRating" itemscope itemtype="https://schema.org/Rating">
|
||||
<meta itemprop="ratingValue" content="{{ rating.rating|floatformat }}">
|
||||
<p class="mr-1">{% trans "rated it" %}</p>
|
||||
|
||||
{% include 'snippets/stars.html' with rating=rating.rating %}
|
||||
</div>
|
||||
<div>
|
||||
|
|
|
@ -5,15 +5,15 @@
|
|||
{% block title %}{{ series_name }}{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="block">
|
||||
<h1 class="title">{{ series_name }}</h1>
|
||||
<div class="block" itemscope itemtype="https://schema.org/BookSeries">
|
||||
<h1 class="title" itemprop="name">{{ series_name }}</h1>
|
||||
<div class="subtitle" dir="auto">
|
||||
{% trans "Series by" %} <a
|
||||
href="{{ author.local_path }}"
|
||||
class="author {{ link_class }}"
|
||||
itemprop="author"
|
||||
itemprop="creator"
|
||||
itemscope
|
||||
itemtype="https://schema.org/Thing"
|
||||
itemtype="https://schema.org/Person"
|
||||
><span
|
||||
itemprop="name"
|
||||
>{{ author.name }}</span></a>
|
||||
|
@ -22,6 +22,7 @@
|
|||
<div class="columns is-multiline is-mobile">
|
||||
{% for book in books %}
|
||||
{% with book=book %}
|
||||
{# @todo Set `hasPart` property in some meaningful way #}
|
||||
<div class="column is-one-fifth-tablet is-half-mobile is-flex is-flex-direction-column">
|
||||
<div class="is-flex-grow-1 mb-3">
|
||||
<span class="subtitle">{% if book.series_number %}{% blocktrans with series_number=book.series_number %}Book {{ series_number }}{% endblocktrans %}{% else %}{% trans 'Unsorted Book' %}{% endif %}</span>
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
<base target="_blank">
|
||||
|
||||
<link rel="shortcut icon" type="image/x-icon" href="{% if site.favicon %}{% get_media_prefix %}{{ site.favicon }}{% else %}{% static "images/favicon.ico" %}{% endif %}">
|
||||
<link rel="manifest" href="/manifest.json" />
|
||||
</head>
|
||||
<body>
|
||||
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
|
||||
<link rel="shortcut icon" type="image/x-icon" href="{% if site.favicon %}{% get_media_prefix %}{{ site.favicon }}{% else %}{% static "images/favicon.ico" %}{% endif %}">
|
||||
<link rel="apple-touch-icon" href="{% if site.logo %}{{ media_full_url }}{{ site.logo }}{% else %}{% static "images/logo.png" %}{% endif %}">
|
||||
<link rel="manifest" href="/manifest.json" />
|
||||
|
||||
{% block opengraph %}
|
||||
{% include 'snippets/opengraph.html' %}
|
||||
|
@ -129,7 +130,12 @@
|
|||
</div>
|
||||
<div class="column">
|
||||
<label class="is-sr-only" for="id_password">{% trans "Password:" %}</label>
|
||||
<input type="password" name="password" maxlength="128" class="input" required="" id="id_password" placeholder="{% trans 'password' %}">
|
||||
<div class="control has-icons-right">
|
||||
<input type="password" name="password" maxlength="128" class="input" required="" id="id_password" placeholder="{% trans 'password' %}">
|
||||
<span data-password-icon data-for="id_password" class="icon is-right is-clickable">
|
||||
<button type="button" aria-controls="id_password" class="icon-eye-blocked" title="{% trans 'Show/Hide password' %}"></button>
|
||||
</span>
|
||||
</div>
|
||||
<p class="help"><a href="{% url 'password-reset' %}">{% trans "Forgot your password?" %}</a></p>
|
||||
</div>
|
||||
<div class="column is-narrow">
|
||||
|
|
14
bookwyrm/templates/manifest.json
Normal file
14
bookwyrm/templates/manifest.json
Normal file
|
@ -0,0 +1,14 @@
|
|||
{% load static %}
|
||||
{
|
||||
"name": "{{ site.name }}",
|
||||
"description": "{{ site.description }}",
|
||||
"icons": [
|
||||
{
|
||||
"src": "{% if site.logo %}{{ media_full_url }}{{ site.logo }}{% else %}{% static 'images/logo.png' %}{% endif %}",
|
||||
"type": "image/png",
|
||||
"sizes": "512x512"
|
||||
}
|
||||
],
|
||||
"start_url": "/",
|
||||
"display": "standalone"
|
||||
}
|
|
@ -6,14 +6,6 @@
|
|||
{% load humanize %}
|
||||
|
||||
{% with status_type=status.status_type %}
|
||||
<div
|
||||
class="block"
|
||||
{% if status_type == "Review" %}
|
||||
itemprop="rating"
|
||||
itemtype="https://schema.org/Rating"
|
||||
{% endif %}
|
||||
>
|
||||
|
||||
<div class="columns is-gapless">
|
||||
{% if not hide_book %}
|
||||
{% with book=status.book|default:status.mention_books.first %}
|
||||
|
@ -58,9 +50,6 @@
|
|||
{% endif %}
|
||||
>
|
||||
<meta itemprop="ratingValue" content="{{ status.rating|floatformat }}">
|
||||
|
||||
{# @todo Is it possible to not hard-code the value? #}
|
||||
<meta itemprop="bestRating" content="5">
|
||||
</span>
|
||||
{% include 'snippets/stars.html' with rating=status.rating %}
|
||||
</h4>
|
||||
|
@ -154,6 +143,5 @@
|
|||
</div>
|
||||
</article>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% endwith %}
|
||||
|
|
|
@ -16,9 +16,6 @@
|
|||
>
|
||||
<span class="is-hidden" {{ rating_type }}>
|
||||
<meta itemprop="ratingValue" content="{{ status.rating|floatformat }}">
|
||||
|
||||
{# @todo Is it possible to not hard-code the value? #}
|
||||
<meta itemprop="bestRating" content="5">
|
||||
</span>
|
||||
</span>
|
||||
</span>
|
||||
|
|
|
@ -92,7 +92,23 @@ class Book(TestCase):
|
|||
book.published_date = timezone.make_aware(parse("2020"))
|
||||
book.save()
|
||||
self.assertEqual(book.edition_info, "worm, Glorbish language, 2020")
|
||||
self.assertEqual(book.alt_text, "Test Edition (worm, Glorbish language, 2020)")
|
||||
|
||||
def test_alt_text(self):
|
||||
"""text slug used for cover images"""
|
||||
book = models.Edition.objects.create(title="Test Edition")
|
||||
author = models.Author.objects.create(name="Author Name")
|
||||
|
||||
self.assertEqual(book.alt_text, "Test Edition")
|
||||
|
||||
book.authors.set([author])
|
||||
book.save()
|
||||
|
||||
self.assertEqual(book.alt_text, "Author Name: Test Edition")
|
||||
|
||||
book.physical_format = "worm"
|
||||
book.published_date = timezone.make_aware(parse("2022"))
|
||||
|
||||
self.assertEqual(book.alt_text, "Author Name: Test Edition (worm, 2022)")
|
||||
|
||||
def test_get_rank(self):
|
||||
"""sets the data quality index for the book"""
|
||||
|
|
|
@ -314,6 +314,29 @@ class Status(TestCase):
|
|||
)
|
||||
self.assertEqual(activity["attachment"][0]["name"], "Test Edition")
|
||||
|
||||
def test_quotation_with_author_to_pure_activity(self, *_):
|
||||
"""serialization of quotation of a book with author and edition info"""
|
||||
self.book.authors.set([models.Author.objects.create(name="Author Name")])
|
||||
self.book.physical_format = "worm"
|
||||
self.book.save()
|
||||
status = models.Quotation.objects.create(
|
||||
quote="quote",
|
||||
content="",
|
||||
user=self.local_user,
|
||||
book=self.book,
|
||||
)
|
||||
activity = status.to_activity(pure=True)
|
||||
self.assertEqual(
|
||||
activity["content"],
|
||||
(
|
||||
f'quote <p>— Author Name: <a href="{self.book.remote_id}">'
|
||||
"<i>Test Edition</i></a></p>"
|
||||
),
|
||||
)
|
||||
self.assertEqual(
|
||||
activity["attachment"][0]["name"], "Author Name: Test Edition (worm)"
|
||||
)
|
||||
|
||||
def test_quotation_page_serialization(self, *_):
|
||||
"""serialization of quotation page position"""
|
||||
tests = [
|
||||
|
|
|
@ -7,6 +7,7 @@ from django.core.files.uploadedfile import SimpleUploadedFile
|
|||
from django.template.response import TemplateResponse
|
||||
from django.test import TestCase
|
||||
from django.test.client import RequestFactory
|
||||
from django.utils import timezone
|
||||
|
||||
from bookwyrm import forms, models, views
|
||||
from bookwyrm.tests.validate_html import validate_html
|
||||
|
@ -128,7 +129,7 @@ class ImportViews(TestCase):
|
|||
|
||||
def test_get_average_import_time_with_data(self):
|
||||
"""Now, with data"""
|
||||
now = datetime.datetime.now()
|
||||
now = timezone.now()
|
||||
two_hours_ago = now - datetime.timedelta(hours=2)
|
||||
four_hours_ago = now - datetime.timedelta(hours=4)
|
||||
models.ImportJob.objects.create(
|
||||
|
@ -152,7 +153,7 @@ class ImportViews(TestCase):
|
|||
|
||||
def test_get_average_import_time_ignore_stopped(self):
|
||||
"""Don't include stopped, do include no status"""
|
||||
now = datetime.datetime.now()
|
||||
now = timezone.now()
|
||||
two_hours_ago = now - datetime.timedelta(hours=2)
|
||||
four_hours_ago = now - datetime.timedelta(hours=4)
|
||||
models.ImportJob.objects.create(
|
||||
|
|
|
@ -34,6 +34,12 @@ urlpatterns = [
|
|||
"robots.txt",
|
||||
TemplateView.as_view(template_name="robots.txt", content_type="text/plain"),
|
||||
),
|
||||
path(
|
||||
"manifest.json",
|
||||
TemplateView.as_view(
|
||||
template_name="manifest.json", content_type="application/json"
|
||||
),
|
||||
),
|
||||
# federation endpoints
|
||||
re_path(r"^inbox/?$", views.Inbox.as_view(), name="inbox"),
|
||||
re_path(rf"{LOCAL_USER_PATH}/inbox/?$", views.Inbox.as_view(), name="user_inbox"),
|
||||
|
|
78
bump-version.sh
Normal file
78
bump-version.sh
Normal file
|
@ -0,0 +1,78 @@
|
|||
#!/bin/bash
|
||||
|
||||
NOW="$(date +'%B %d, %Y')"
|
||||
RED="\033[1;31m"
|
||||
GREEN="\033[0;32m"
|
||||
YELLOW="\033[1;33m"
|
||||
BLUE="\033[1;34m"
|
||||
PURPLE="\033[1;35m"
|
||||
CYAN="\033[1;36m"
|
||||
WHITE="\033[1;37m"
|
||||
RESET="\033[0m"
|
||||
|
||||
LATEST_HASH=`git log --pretty=format:'%h' -n 1`
|
||||
|
||||
QUESTION_FLAG="${GREEN}?"
|
||||
WARNING_FLAG="${YELLOW}!"
|
||||
NOTICE_FLAG="${CYAN}❯"
|
||||
|
||||
# ADJUSTMENTS_MSG="${QUESTION_FLAG} ${CYAN}Now you can make adjustments to ${WHITE}CHANGELOG.md${CYAN}. Then press enter to continue."
|
||||
PUSHING_MSG="${NOTICE_FLAG} Pushing new version to the ${WHITE}origin${CYAN}..."
|
||||
|
||||
if [ -f VERSION ]; then
|
||||
BASE_STRING=`cat VERSION`
|
||||
BASE_LIST=(`echo $BASE_STRING | tr '.' ' '`)
|
||||
V_MAJOR=${BASE_LIST[0]}
|
||||
V_MINOR=${BASE_LIST[1]}
|
||||
V_PATCH=${BASE_LIST[2]}
|
||||
echo -e "${NOTICE_FLAG} Current version: ${WHITE}$BASE_STRING"
|
||||
echo -e "${NOTICE_FLAG} Latest commit hash: ${WHITE}$LATEST_HASH"
|
||||
V_MINOR=$((V_MINOR + 1))
|
||||
V_PATCH=0
|
||||
SUGGESTED_VERSION="$V_MAJOR.$V_MINOR.$V_PATCH"
|
||||
echo -ne "${QUESTION_FLAG} ${CYAN}Enter a version number [${WHITE}$SUGGESTED_VERSION${CYAN}]: "
|
||||
read INPUT_STRING
|
||||
if [ "$INPUT_STRING" = "" ]; then
|
||||
INPUT_STRING=$SUGGESTED_VERSION
|
||||
fi
|
||||
echo -e "${NOTICE_FLAG} Will set new version to be ${WHITE}$INPUT_STRING"
|
||||
echo $INPUT_STRING > VERSION
|
||||
# echo "## $INPUT_STRING ($NOW)" > tmpfile
|
||||
# git log --pretty=format:" - %s" "v$BASE_STRING"...HEAD >> tmpfile
|
||||
# echo "" >> tmpfile
|
||||
# echo "" >> tmpfile
|
||||
# cat CHANGELOG.md >> tmpfile
|
||||
# mv tmpfile CHANGELOG.md
|
||||
# echo -e "$ADJUSTMENTS_MSG"
|
||||
# read
|
||||
echo -e "$PUSHING_MSG"
|
||||
# git add CHANGELOG.md VERSION
|
||||
git commit -m "Bump version to ${INPUT_STRING}."
|
||||
git tag -a -m "Tag version ${INPUT_STRING}." "v$INPUT_STRING"
|
||||
git push origin --tags
|
||||
else
|
||||
echo -e "${WARNING_FLAG} Could not find a VERSION file."
|
||||
echo -ne "${QUESTION_FLAG} ${CYAN}Do you want to create a version file and start from scratch? [${WHITE}y${CYAN}]: "
|
||||
read RESPONSE
|
||||
if [ "$RESPONSE" = "" ]; then RESPONSE="y"; fi
|
||||
if [ "$RESPONSE" = "Y" ]; then RESPONSE="y"; fi
|
||||
if [ "$RESPONSE" = "Yes" ]; then RESPONSE="y"; fi
|
||||
if [ "$RESPONSE" = "yes" ]; then RESPONSE="y"; fi
|
||||
if [ "$RESPONSE" = "YES" ]; then RESPONSE="y"; fi
|
||||
if [ "$RESPONSE" = "y" ]; then
|
||||
echo "0.1.0" > VERSION
|
||||
echo "## 0.1.0 ($NOW)" > CHANGELOG.md
|
||||
# git log --pretty=format:" - %s" >> CHANGELOG.md
|
||||
# echo "" >> CHANGELOG.md
|
||||
# echo "" >> CHANGELOG.md
|
||||
# echo -e "$ADJUSTMENTS_MSG"
|
||||
# read
|
||||
echo -e "$PUSHING_MSG"
|
||||
git add VERSION CHANGELOG.md
|
||||
git commit -m "Add VERSION and CHANGELOG.md files, Bump version to v0.1.0."
|
||||
git tag -a -m "Tag version 0.1.0." "v0.1.0"
|
||||
git push origin --tags
|
||||
fi
|
||||
fi
|
||||
|
||||
echo -e "${NOTICE_FLAG} Finished."
|
18
bw-dev
18
bw-dev
|
@ -188,27 +188,25 @@ case "$CMD" in
|
|||
;;
|
||||
prettier)
|
||||
prod_error
|
||||
$DOCKER_COMPOSE run --rm dev-tools npx prettier --write bookwyrm/static/js/*.js
|
||||
$DOCKER_COMPOSE run --rm dev-tools prettier --write bookwyrm/static/js/*.js
|
||||
;;
|
||||
eslint)
|
||||
prod_error
|
||||
$DOCKER_COMPOSE run --rm dev-tools npx eslint bookwyrm/static --ext .js
|
||||
$DOCKER_COMPOSE run --rm dev-tools eslint bookwyrm/static --ext .js
|
||||
;;
|
||||
stylelint)
|
||||
prod_error
|
||||
$DOCKER_COMPOSE run --rm dev-tools npx stylelint \
|
||||
bookwyrm/static/css/bookwyrm.scss bookwyrm/static/css/bookwyrm/**/*.scss --fix \
|
||||
--config dev-tools/.stylelintrc.js
|
||||
$DOCKER_COMPOSE run --rm dev-tools stylelint --fix bookwyrm/static/css \
|
||||
--config dev-tools/.stylelintrc.js --ignore-path dev-tools/.stylelintignore
|
||||
;;
|
||||
formatters)
|
||||
prod_error
|
||||
runweb pylint bookwyrm/
|
||||
$DOCKER_COMPOSE run --rm dev-tools black celerywyrm bookwyrm
|
||||
$DOCKER_COMPOSE run --rm dev-tools npx prettier --write bookwyrm/static/js/*.js
|
||||
$DOCKER_COMPOSE run --rm dev-tools npx eslint bookwyrm/static --ext .js
|
||||
$DOCKER_COMPOSE run --rm dev-tools npx stylelint \
|
||||
bookwyrm/static/css/bookwyrm.scss bookwyrm/static/css/bookwyrm/**/*.scss --fix \
|
||||
--config dev-tools/.stylelintrc.js
|
||||
$DOCKER_COMPOSE run --rm dev-tools prettier --write bookwyrm/static/js/*.js
|
||||
$DOCKER_COMPOSE run --rm dev-tools eslint bookwyrm/static --ext .js
|
||||
$DOCKER_COMPOSE run --rm dev-tools stylelint --fix bookwyrm/static/css \
|
||||
--config dev-tools/.stylelintrc.js --ignore-path dev-tools/.stylelintignore
|
||||
;;
|
||||
mypy)
|
||||
prod_error
|
||||
|
|
|
@ -5,10 +5,30 @@ After=network.target postgresql.service redis.service
|
|||
[Service]
|
||||
User=bookwyrm
|
||||
Group=bookwyrm
|
||||
WorkingDirectory=/opt/bookwyrm/
|
||||
WorkingDirectory=/opt/bookwyrm
|
||||
ExecStart=/opt/bookwyrm/venv/bin/celery -A celerywyrm beat -l INFO --scheduler django_celery_beat.schedulers:DatabaseScheduler
|
||||
StandardOutput=journal
|
||||
StandardError=inherit
|
||||
ProtectSystem=strict
|
||||
ProtectHome=tmpfs
|
||||
InaccessiblePaths=-/media -/mnt -/srv
|
||||
PrivateTmp=yes
|
||||
TemporaryFileSystem=/var /run /opt
|
||||
PrivateUsers=true
|
||||
PrivateDevices=true
|
||||
BindReadOnlyPaths=/opt/bookwyrm
|
||||
BindPaths=/opt/bookwyrm/images /opt/bookwyrm/static /var/run/postgresql
|
||||
LockPersonality=yes
|
||||
MemoryDenyWriteExecute=true
|
||||
PrivateMounts=true
|
||||
ProtectHostname=true
|
||||
ProtectClock=true
|
||||
ProtectKernelTunables=true
|
||||
ProtectKernelModules=true
|
||||
ProtectKernelLogs=true
|
||||
ProtectControlGroups=true
|
||||
RestrictRealtime=true
|
||||
RestrictNamespaces=net
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
|
|
|
@ -5,10 +5,30 @@ After=network.target postgresql.service redis.service
|
|||
[Service]
|
||||
User=bookwyrm
|
||||
Group=bookwyrm
|
||||
WorkingDirectory=/opt/bookwyrm/
|
||||
WorkingDirectory=/opt/bookwyrm
|
||||
ExecStart=/opt/bookwyrm/venv/bin/celery -A celerywyrm worker -l info -Q high_priority,medium_priority,low_priority,streams,images,suggested_users,email,connectors,lists,inbox,imports,import_triggered,broadcast,misc
|
||||
StandardOutput=journal
|
||||
StandardError=inherit
|
||||
ProtectSystem=strict
|
||||
ProtectHome=tmpfs
|
||||
InaccessiblePaths=-/media -/mnt -/srv
|
||||
PrivateTmp=yes
|
||||
TemporaryFileSystem=/var /run /opt
|
||||
PrivateUsers=true
|
||||
PrivateDevices=true
|
||||
BindReadOnlyPaths=/opt/bookwyrm
|
||||
BindPaths=/opt/bookwyrm/images /opt/bookwyrm/static /var/run/postgresql
|
||||
LockPersonality=yes
|
||||
MemoryDenyWriteExecute=true
|
||||
PrivateMounts=true
|
||||
ProtectHostname=true
|
||||
ProtectClock=true
|
||||
ProtectKernelTunables=true
|
||||
ProtectKernelModules=true
|
||||
ProtectKernelLogs=true
|
||||
ProtectControlGroups=true
|
||||
RestrictRealtime=true
|
||||
RestrictNamespaces=net
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
|
|
|
@ -2,13 +2,33 @@
|
|||
Description=BookWyrm
|
||||
After=network.target postgresql.service redis.service
|
||||
|
||||
[Service]
|
||||
[Service]P
|
||||
User=bookwyrm
|
||||
Group=bookwyrm
|
||||
WorkingDirectory=/opt/bookwyrm/
|
||||
ExecStart=/opt/bookwyrm/venv/bin/gunicorn bookwyrm.wsgi:application --threads=8 --bind 0.0.0.0:8000
|
||||
WorkingDirectory=/opt/bookwyrm
|
||||
ExecStart=/opt/bookwyrm/venv/bin/gunicorn bookwyrm.wsgi:application --bind 0.0.0.0:8000
|
||||
StandardOutput=journal
|
||||
StandardError=inherit
|
||||
ProtectSystem=strict
|
||||
ProtectHome=tmpfs
|
||||
InaccessiblePaths=-/media -/mnt -/srv
|
||||
PrivateTmp=yes
|
||||
TemporaryFileSystem=/var /run /opt
|
||||
PrivateUsers=true
|
||||
PrivateDevices=true
|
||||
BindReadOnlyPaths=/opt/bookwyrm
|
||||
BindPaths=/opt/bookwyrm/images /opt/bookwyrm/static /var/run/postgresql
|
||||
LockPersonality=yes
|
||||
MemoryDenyWriteExecute=true
|
||||
PrivateMounts=true
|
||||
ProtectHostname=true
|
||||
ProtectClock=true
|
||||
ProtectKernelTunables=true
|
||||
ProtectKernelModules=true
|
||||
ProtectKernelLogs=true
|
||||
ProtectControlGroups=true
|
||||
RestrictRealtime=true
|
||||
RestrictNamespaces=net
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
|
|
|
@ -1 +1,2 @@
|
|||
**/vendor/**
|
||||
**/fonts/**
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/* global module */
|
||||
|
||||
module.exports = {
|
||||
"extends": "stylelint-config-standard",
|
||||
"extends": "stylelint-config-standard-scss",
|
||||
|
||||
"plugins": [
|
||||
"stylelint-order"
|
||||
|
@ -18,5 +18,13 @@ module.exports = {
|
|||
"declaration-block-no-redundant-longhand-properties": null,
|
||||
"no-descending-specificity": null,
|
||||
"alpha-value-notation": null
|
||||
}
|
||||
},
|
||||
"overrides": [
|
||||
{
|
||||
"files": [ "../**/themes/bookwyrm-*.scss" ],
|
||||
"rules": {
|
||||
"no-invalid-position-at-import-rule": null
|
||||
}
|
||||
}
|
||||
]
|
||||
};
|
||||
|
|
|
@ -1,14 +1,17 @@
|
|||
FROM python:3.9
|
||||
WORKDIR /app/dev-tools
|
||||
|
||||
ENV PYTHONUNBUFFERED 1
|
||||
ENV PATH="/app/dev-tools/node_modules/.bin:$PATH"
|
||||
ENV PYTHONUNBUFFERED=1
|
||||
ENV NPM_CONFIG_UPDATE_NOTIFIER=false
|
||||
ENV PIP_ROOT_USER_ACTION=ignore PIP_DISABLE_PIP_VERSION_CHECK=1
|
||||
|
||||
COPY nodejs.sources /etc/apt/sources.list.d/
|
||||
COPY package.json requirements.txt .stylelintrc.js .stylelintignore /app/dev-tools/
|
||||
|
||||
RUN apt-get update && \
|
||||
apt-get install -y nodejs && \
|
||||
pip install -r requirements.txt && \
|
||||
npm install .
|
||||
|
||||
RUN mkdir /app
|
||||
WORKDIR /app
|
||||
|
||||
COPY package.json requirements.txt .stylelintrc.js .stylelintignore /app/
|
||||
RUN pip install -r requirements.txt
|
||||
|
||||
RUN apt-get update && apt-get install -y curl
|
||||
RUN curl -sL https://deb.nodesource.com/setup_18.x | bash -
|
||||
RUN apt-get install -y nodejs && apt-get clean
|
||||
RUN npm install .
|
||||
|
|
34
dev-tools/nodejs.sources
Normal file
34
dev-tools/nodejs.sources
Normal file
|
@ -0,0 +1,34 @@
|
|||
Types: deb
|
||||
URIs: https://deb.nodesource.com/node_18.x
|
||||
Suites: nodistro
|
||||
Components: main
|
||||
Signed-By:
|
||||
-----BEGIN PGP PUBLIC KEY BLOCK-----
|
||||
.
|
||||
mQENBFdDN1ABCADaNd/I3j3tn40deQNgz7hB2NvT+syXe6k4ZmdiEcOfBvFrkS8B
|
||||
hNS67t93etHsxEy7E0qwsZH32bKazMqe9zDwoa3aVImryjh6SHC9lMtW27JPHFeM
|
||||
Srkt9YmH1WMwWcRO6eSY9B3PpazquhnvbammLuUojXRIxkDroy6Fw4UKmUNSRr32
|
||||
9Ej87jRoR1B2/57Kfp2Y4+vFGGzSvh3AFQpBHq51qsNHALU6+8PjLfIt+5TPvaWR
|
||||
TB+kAZnQZkaIQM2nr1n3oj6ak2RATY/+kjLizgFWzgEfbCrbsyq68UoY5FPBnu4Z
|
||||
E3iDZpaIqwKr0seUC7iA1xM5eHi5kty1oB7HABEBAAG0Ik5Tb2xpZCA8bnNvbGlk
|
||||
LWdwZ0Bub2Rlc291cmNlLmNvbT6JATgEEwECACIFAldDN1ACGwMGCwkIBwMCBhUI
|
||||
AgkKCwQWAgMBAh4BAheAAAoJEC9ZtfmbG+C0y7wH/i4xnab36dtrYW7RZwL8i6Sc
|
||||
NjMx4j9+U1kr/F6YtqWd+JwCbBdar5zRghxPcYEq/qf7MbgAYcs1eSOuTOb7n7+o
|
||||
xUwdH2iCtHhKh3Jr2mRw1ks7BbFZPB5KmkxHaEBfLT4d+I91ZuUdPXJ+0SXs9gzk
|
||||
Dbz65Uhoz3W03aiF8HeL5JNARZFMbHHNVL05U1sTGTCOtu+1c/33f3TulQ/XZ3Y4
|
||||
hwGCpLe0Tv7g7Lp3iLMZMWYPEa0a7S4u8he5IEJQLd8bE8jltcQvrdr3Fm8kI2Jg
|
||||
BJmUmX4PSfhuTCFaR/yeCt3UoW883bs9LfbTzIx9DJGpRIu8Y0IL3b4sj/GoZVq5
|
||||
AQ0EV0M3UAEIAKrTaC62ayzqOIPa7nS90BHHck4Z33a2tZF/uof38xNOiyWGhT8u
|
||||
JeFoTTHn5SQq5Ftyu4K3K2fbbpuu/APQF05AaljzVkDGNMW4pSkgOasdysj831cu
|
||||
ssrHX2RYS22wg80k6C/Hwmh5F45faEuNxsV+bPx7oPUrt5n6GMx84vEP3i1+FDBi
|
||||
0pt/B/QnDFBXki1BGvJ35f5NwDefK8VaInxXP3ZN/WIbtn5dqxppkV/YkO7GiJlp
|
||||
Jlju9rf3kKUIQzKQWxFsbCAPIHoWv7rH9RSxgDithXtG6Yg5R1aeBbJaPNXL9wpJ
|
||||
YBJbiMjkAFaz4B95FOqZm3r7oHugiCGsHX0AEQEAAYkBHwQYAQIACQUCV0M3UAIb
|
||||
DAAKCRAvWbX5mxvgtE/OB/0VN88DR3Y3fuqy7lq/dthkn7Dqm9YXdorZl3L152eE
|
||||
IF882aG8FE3qZdaLGjQO4oShAyNWmRfSGuoH0XERXAI9n0r8m4mDMxE6rtP7tHet
|
||||
y/5M8x3CTyuMgx5GLDaEUvBusnTD+/v/fBMwRK/cZ9du5PSG4R50rtst+oYyC2ao
|
||||
x4I2SgjtF/cY7bECsZDplzatN3gv34PkcdIg8SLHAVlL4N5tzumDeizRspcSyoy2
|
||||
K2+hwKU4C4+dekLLTg8rjnRROvplV2KtaEk6rxKtIRFDCoQng8wfJuIMrDNKvqZw
|
||||
FRGt7cbvW5MCnuH8MhItOl9Uxp1wHp6gtav/h8Gp6MBa
|
||||
=MARt
|
||||
-----END PGP PUBLIC KEY BLOCK-----
|
|
@ -11,6 +11,7 @@
|
|||
"stylelint-config-recommended": "^7.0.0",
|
||||
"stylelint-config-standard": "^25.0.0",
|
||||
"stylelint-order": "^5.0.0",
|
||||
"stylelint-config-standard-scss": "^3.0.0",
|
||||
"watch": "^0.13.0"
|
||||
},
|
||||
"dependencies": {
|
||||
|
|
|
@ -130,6 +130,7 @@ services:
|
|||
build: dev-tools
|
||||
env_file: .env
|
||||
volumes:
|
||||
- /app/dev-tools/
|
||||
- .:/app
|
||||
volumes:
|
||||
pgdata:
|
||||
|
|
788
poetry.lock
generated
788
poetry.lock
generated
File diff suppressed because it is too large
Load diff
|
@ -25,7 +25,7 @@ gunicorn = "20.0.4"
|
|||
libsass = "0.22.0"
|
||||
Markdown = "3.4.1"
|
||||
packaging = "21.3"
|
||||
Pillow = "^9.4.0"
|
||||
Pillow = "10.0.1"
|
||||
psycopg2 = "2.9.5"
|
||||
pycryptodome = "3.16.0"
|
||||
python-dateutil = "2.8.2"
|
||||
|
|
Loading…
Add table
Reference in a new issue