mirror of
https://github.com/bookwyrm-social/bookwyrm.git
synced 2024-05-20 09:18:19 +00:00
Compare commits
6 commits
5fcdfbc9c6
...
3963fa9579
Author | SHA1 | Date | |
---|---|---|---|
3963fa9579 | |||
3ade7ca420 | |||
ebba70db6e | |||
d652183e33 | |||
39c811c76e | |||
6096332f74 |
17
.github/workflows/black.yml
vendored
17
.github/workflows/black.yml
vendored
|
@ -1,17 +0,0 @@
|
|||
name: Python Formatting (run ./bw-dev black to fix)
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ main ]
|
||||
pull_request:
|
||||
branches: [ main ]
|
||||
|
||||
jobs:
|
||||
lint:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/setup-python@v4
|
||||
- uses: psf/black@22.12.0
|
||||
with:
|
||||
version: 22.12.0
|
2
.github/workflows/codeql-analysis.yml
vendored
2
.github/workflows/codeql-analysis.yml
vendored
|
@ -36,7 +36,7 @@ jobs:
|
|||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
|
||||
# Initializes the CodeQL tools for scanning.
|
||||
- name: Initialize CodeQL
|
||||
|
|
2
.github/workflows/curlylint.yaml
vendored
2
.github/workflows/curlylint.yaml
vendored
|
@ -10,7 +10,7 @@ jobs:
|
|||
lint:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Install curlylint
|
||||
run: pip install curlylint
|
||||
|
|
70
.github/workflows/django-tests.yml
vendored
70
.github/workflows/django-tests.yml
vendored
|
@ -1,70 +0,0 @@
|
|||
name: Run Python Tests
|
||||
on:
|
||||
push:
|
||||
branches: [ main ]
|
||||
pull_request:
|
||||
branches: [ main ]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
|
||||
runs-on: ubuntu-20.04
|
||||
services:
|
||||
postgres:
|
||||
image: postgres:13
|
||||
env:
|
||||
POSTGRES_USER: postgres
|
||||
POSTGRES_PASSWORD: hunter2
|
||||
options: >-
|
||||
--health-cmd pg_isready
|
||||
--health-interval 10s
|
||||
--health-timeout 5s
|
||||
--health-retries 5
|
||||
ports:
|
||||
- 5432:5432
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: 3.9
|
||||
- name: Install Dependencies
|
||||
run: |
|
||||
python -m pip install --upgrade pip
|
||||
pip install -r requirements.txt
|
||||
- name: Check migrations up-to-date
|
||||
run: |
|
||||
python ./manage.py makemigrations --check
|
||||
env:
|
||||
SECRET_KEY: beepbeep
|
||||
DOMAIN: your.domain.here
|
||||
EMAIL_HOST: ""
|
||||
EMAIL_HOST_USER: ""
|
||||
EMAIL_HOST_PASSWORD: ""
|
||||
- name: Run Tests
|
||||
env:
|
||||
SECRET_KEY: beepbeep
|
||||
DEBUG: false
|
||||
USE_HTTPS: true
|
||||
DOMAIN: your.domain.here
|
||||
BOOKWYRM_DATABASE_BACKEND: postgres
|
||||
MEDIA_ROOT: images/
|
||||
POSTGRES_PASSWORD: hunter2
|
||||
POSTGRES_USER: postgres
|
||||
POSTGRES_DB: github_actions
|
||||
POSTGRES_HOST: 127.0.0.1
|
||||
CELERY_BROKER: ""
|
||||
REDIS_BROKER_PORT: 6379
|
||||
REDIS_BROKER_PASSWORD: beep
|
||||
USE_DUMMY_CACHE: true
|
||||
FLOWER_PORT: 8888
|
||||
EMAIL_HOST: "smtp.mailgun.org"
|
||||
EMAIL_PORT: 587
|
||||
EMAIL_HOST_USER: ""
|
||||
EMAIL_HOST_PASSWORD: ""
|
||||
EMAIL_USE_TLS: true
|
||||
ENABLE_PREVIEW_IMAGES: false
|
||||
ENABLE_THUMBNAIL_GENERATION: true
|
||||
HTTP_X_FORWARDED_PROTO: false
|
||||
run: |
|
||||
pytest -n 3
|
2
.github/workflows/lint-frontend.yaml
vendored
2
.github/workflows/lint-frontend.yaml
vendored
|
@ -19,7 +19,7 @@ jobs:
|
|||
|
||||
steps:
|
||||
# Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it.
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Install modules
|
||||
run: npm install stylelint stylelint-config-recommended stylelint-config-standard stylelint-order eslint
|
||||
|
|
50
.github/workflows/mypy.yml
vendored
50
.github/workflows/mypy.yml
vendored
|
@ -1,50 +0,0 @@
|
|||
name: Mypy
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ main ]
|
||||
pull_request:
|
||||
branches: [ main ]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Set up Python 3.9
|
||||
uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: 3.9
|
||||
- name: Install Dependencies
|
||||
run: |
|
||||
python -m pip install --upgrade pip
|
||||
pip install -r requirements.txt
|
||||
- name: Analysing the code with mypy
|
||||
env:
|
||||
SECRET_KEY: beepbeep
|
||||
DEBUG: false
|
||||
USE_HTTPS: true
|
||||
DOMAIN: your.domain.here
|
||||
BOOKWYRM_DATABASE_BACKEND: postgres
|
||||
MEDIA_ROOT: images/
|
||||
POSTGRES_PASSWORD: hunter2
|
||||
POSTGRES_USER: postgres
|
||||
POSTGRES_DB: github_actions
|
||||
POSTGRES_HOST: 127.0.0.1
|
||||
CELERY_BROKER: ""
|
||||
REDIS_BROKER_PORT: 6379
|
||||
REDIS_BROKER_PASSWORD: beep
|
||||
USE_DUMMY_CACHE: true
|
||||
FLOWER_PORT: 8888
|
||||
EMAIL_HOST: "smtp.mailgun.org"
|
||||
EMAIL_PORT: 587
|
||||
EMAIL_HOST_USER: ""
|
||||
EMAIL_HOST_PASSWORD: ""
|
||||
EMAIL_USE_TLS: true
|
||||
ENABLE_PREVIEW_IMAGES: false
|
||||
ENABLE_THUMBNAIL_GENERATION: true
|
||||
HTTP_X_FORWARDED_PROTO: false
|
||||
run: |
|
||||
mypy bookwyrm celerywyrm
|
2
.github/workflows/prettier.yaml
vendored
2
.github/workflows/prettier.yaml
vendored
|
@ -14,7 +14,7 @@ jobs:
|
|||
|
||||
steps:
|
||||
# Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it.
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Install modules
|
||||
run: npm install prettier@2.5.1
|
||||
|
|
27
.github/workflows/pylint.yml
vendored
27
.github/workflows/pylint.yml
vendored
|
@ -1,27 +0,0 @@
|
|||
name: Pylint
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ main ]
|
||||
pull_request:
|
||||
branches: [ main ]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Set up Python 3.9
|
||||
uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: 3.9
|
||||
- name: Install Dependencies
|
||||
run: |
|
||||
python -m pip install --upgrade pip
|
||||
pip install -r requirements.txt
|
||||
- name: Analysing the code with pylint
|
||||
run: |
|
||||
pylint bookwyrm/
|
||||
|
99
.github/workflows/python.yml
vendored
Normal file
99
.github/workflows/python.yml
vendored
Normal file
|
@ -0,0 +1,99 @@
|
|||
name: Python
|
||||
on:
|
||||
push:
|
||||
branches: [ main ]
|
||||
pull_request:
|
||||
branches: [ main ]
|
||||
|
||||
# overrides for .env.example
|
||||
env:
|
||||
POSTGRES_HOST: 127.0.0.1
|
||||
PGPORT: 5432
|
||||
POSTGRES_USER: postgres
|
||||
POSTGRES_PASSWORD: hunter2
|
||||
POSTGRES_DB: github_actions
|
||||
SECRET_KEY: beepbeep
|
||||
EMAIL_HOST_USER: ""
|
||||
EMAIL_HOST_PASSWORD: ""
|
||||
|
||||
jobs:
|
||||
pytest:
|
||||
name: Tests (pytest)
|
||||
runs-on: ubuntu-latest
|
||||
services:
|
||||
postgres:
|
||||
image: postgres:13
|
||||
env: # does not inherit from jobs.build.env
|
||||
POSTGRES_USER: postgres
|
||||
POSTGRES_PASSWORD: hunter2
|
||||
options: >-
|
||||
--health-cmd pg_isready
|
||||
--health-interval 10s
|
||||
--health-timeout 5s
|
||||
--health-retries 5
|
||||
ports:
|
||||
- 5432:5432
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Set up Python 3.9
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: 3.9
|
||||
cache: pip
|
||||
- name: Install Dependencies
|
||||
run: |
|
||||
python -m pip install --upgrade pip
|
||||
pip install -r requirements.txt
|
||||
pip install pytest-github-actions-annotate-failures
|
||||
- name: Set up .env
|
||||
run: cp .env.example .env
|
||||
- name: Check migrations up-to-date
|
||||
run: python ./manage.py makemigrations --check
|
||||
- name: Run Tests
|
||||
run: pytest -n 3
|
||||
|
||||
pylint:
|
||||
name: Linting (pylint)
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Set up Python 3.9
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: 3.9
|
||||
cache: pip
|
||||
- name: Install Dependencies
|
||||
run: |
|
||||
python -m pip install --upgrade pip
|
||||
pip install -r requirements.txt
|
||||
- name: Analyse code with pylint
|
||||
run: pylint bookwyrm/
|
||||
|
||||
mypy:
|
||||
name: Typing (mypy)
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Set up Python 3.9
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: 3.9
|
||||
cache: pip
|
||||
- name: Install Dependencies
|
||||
run: |
|
||||
python -m pip install --upgrade pip
|
||||
pip install -r requirements.txt
|
||||
- name: Set up .env
|
||||
run: cp .env.example .env
|
||||
- name: Analyse code with mypy
|
||||
run: mypy bookwyrm celerywyrm
|
||||
|
||||
black:
|
||||
name: Formatting (black; run ./bw-dev black to fix)
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-python@v5
|
||||
- uses: psf/black@22.12.0
|
||||
with:
|
||||
version: 22.12.0
|
|
@ -1,4 +1,5 @@
|
|||
""" using django model forms """
|
||||
|
||||
from django import forms
|
||||
|
||||
from file_resubmit.widgets import ResubmitImageWidget
|
||||
|
@ -25,7 +26,6 @@ class EditionForm(CustomForm):
|
|||
"subtitle",
|
||||
"description",
|
||||
"series",
|
||||
"series_number",
|
||||
"languages",
|
||||
"subjects",
|
||||
"publishers",
|
||||
|
@ -55,9 +55,6 @@ class EditionForm(CustomForm):
|
|||
attrs={"aria-describedby": "desc_description"}
|
||||
),
|
||||
"series": forms.TextInput(attrs={"aria-describedby": "desc_series"}),
|
||||
"series_number": forms.TextInput(
|
||||
attrs={"aria-describedby": "desc_series_number"}
|
||||
),
|
||||
"subjects": ArrayWidget(),
|
||||
"languages": forms.TextInput(
|
||||
attrs={"aria-describedby": "desc_languages_help desc_languages"}
|
||||
|
@ -116,7 +113,6 @@ class EditionFromWorkForm(CustomForm):
|
|||
"description",
|
||||
"languages",
|
||||
"series",
|
||||
"series_number",
|
||||
"subjects",
|
||||
"subject_places",
|
||||
"cover",
|
||||
|
|
148
bookwyrm/migrations/0196_series_model.py
Normal file
148
bookwyrm/migrations/0196_series_model.py
Normal file
|
@ -0,0 +1,148 @@
|
|||
# Generated by Django 3.2.23 on 2024-02-04 20:27
|
||||
|
||||
import bookwyrm.models.fields
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
def make_series(apps, schema_editor):
|
||||
Edition = apps.get_model("bookwyrm", "Edition")
|
||||
Series = apps.get_model("bookwyrm", "Series")
|
||||
SeriesBook = apps.get_model("bookwyrm", "SeriesBook")
|
||||
|
||||
db_alias = schema_editor.connection.alias
|
||||
|
||||
with_series = (
|
||||
Edition.objects.using(db_alias)
|
||||
.exclude(series_name__isnull=True)
|
||||
.exclude(series_name__exact="")
|
||||
.order_by("series_name", "series_number")
|
||||
)
|
||||
for edition in with_series:
|
||||
# TODO: Try to parse number from series_name if series_number is empty?
|
||||
series, _ = Series.objects.using(db_alias).get_or_create(
|
||||
name=edition.series_name,
|
||||
authors=edition.authors.all(),
|
||||
)
|
||||
SeriesBook.objects.using(db_alias).create(
|
||||
book=edition, series=series, number=edition.series_number
|
||||
)
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("bookwyrm", "0195_alter_user_preferred_language"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RenameField(
|
||||
model_name="book",
|
||||
old_name="series",
|
||||
new_name="series_name",
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name="Series",
|
||||
fields=[
|
||||
(
|
||||
"id",
|
||||
models.AutoField(
|
||||
auto_created=True,
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
verbose_name="ID",
|
||||
),
|
||||
),
|
||||
("created_date", models.DateTimeField(auto_now_add=True)),
|
||||
("updated_date", models.DateTimeField(auto_now=True)),
|
||||
(
|
||||
"remote_id",
|
||||
bookwyrm.models.fields.RemoteIdField(
|
||||
max_length=255,
|
||||
null=True,
|
||||
validators=[bookwyrm.models.fields.validate_remote_id],
|
||||
),
|
||||
),
|
||||
("name", bookwyrm.models.fields.CharField(max_length=100)),
|
||||
(
|
||||
"authors",
|
||||
bookwyrm.models.fields.ManyToManyField(to="bookwyrm.Author"),
|
||||
),
|
||||
],
|
||||
options={
|
||||
"abstract": False,
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name="SeriesBook",
|
||||
fields=[
|
||||
(
|
||||
"id",
|
||||
models.AutoField(
|
||||
auto_created=True,
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
verbose_name="ID",
|
||||
),
|
||||
),
|
||||
("created_date", models.DateTimeField(auto_now_add=True)),
|
||||
("updated_date", models.DateTimeField(auto_now=True)),
|
||||
(
|
||||
"remote_id",
|
||||
bookwyrm.models.fields.RemoteIdField(
|
||||
max_length=255,
|
||||
null=True,
|
||||
validators=[bookwyrm.models.fields.validate_remote_id],
|
||||
),
|
||||
),
|
||||
(
|
||||
"number",
|
||||
bookwyrm.models.fields.CharField(
|
||||
blank=True, max_length=255, null=True
|
||||
),
|
||||
),
|
||||
(
|
||||
"book",
|
||||
models.ForeignKey(
|
||||
on_delete=django.db.models.deletion.PROTECT, to="bookwyrm.book"
|
||||
),
|
||||
),
|
||||
(
|
||||
"series",
|
||||
models.ForeignKey(
|
||||
on_delete=django.db.models.deletion.PROTECT,
|
||||
to="bookwyrm.series",
|
||||
),
|
||||
),
|
||||
],
|
||||
options={
|
||||
"ordering": ["-number"],
|
||||
"unique_together": {("book", "series")},
|
||||
},
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name="series",
|
||||
name="books",
|
||||
field=bookwyrm.models.fields.ManyToManyField(
|
||||
related_name="series_books",
|
||||
through="bookwyrm.SeriesBook",
|
||||
to="bookwyrm.Book",
|
||||
),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name="book",
|
||||
name="series",
|
||||
field=models.ManyToManyField(
|
||||
through="bookwyrm.SeriesBook", to="bookwyrm.Series"
|
||||
),
|
||||
),
|
||||
migrations.RunPython(make_series), # TODO: reverse_code
|
||||
migrations.RemoveField(
|
||||
model_name="book",
|
||||
name="series_number",
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name="book",
|
||||
name="series_name",
|
||||
),
|
||||
]
|
|
@ -1,4 +1,5 @@
|
|||
""" bring all the models into the app namespace """
|
||||
|
||||
import inspect
|
||||
import sys
|
||||
|
||||
|
@ -7,6 +8,8 @@ from .author import Author
|
|||
from .link import Link, FileLink, LinkDomain
|
||||
from .connector import Connector
|
||||
|
||||
from .series import Series, SeriesBook
|
||||
|
||||
from .shelf import Shelf, ShelfBook
|
||||
from .list import List, ListItem
|
||||
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
""" database schema for books and shelves """
|
||||
|
||||
from itertools import chain
|
||||
import re
|
||||
from typing import Any
|
||||
|
@ -120,8 +121,11 @@ class Book(BookDataModel):
|
|||
languages = fields.ArrayField(
|
||||
models.CharField(max_length=255), blank=True, default=list
|
||||
)
|
||||
series = fields.TextField(max_length=255, blank=True, null=True)
|
||||
series_number = fields.CharField(max_length=255, blank=True, null=True)
|
||||
series = models.ManyToManyField(
|
||||
"Series",
|
||||
through="SeriesBook",
|
||||
through_fields=("book", "series"),
|
||||
)
|
||||
subjects = fields.ArrayField(
|
||||
models.CharField(max_length=255), blank=True, null=True, default=list
|
||||
)
|
||||
|
@ -190,9 +194,13 @@ class Book(BookDataModel):
|
|||
"""properties of this edition, as a string"""
|
||||
items = [
|
||||
self.physical_format if hasattr(self, "physical_format") else None,
|
||||
f"{self.languages[0]} language"
|
||||
if self.languages and self.languages[0] and self.languages[0] != "English"
|
||||
else None,
|
||||
(
|
||||
f"{self.languages[0]} language"
|
||||
if self.languages
|
||||
and self.languages[0]
|
||||
and self.languages[0] != "English"
|
||||
else None
|
||||
),
|
||||
str(self.published_date.year) if self.published_date else None,
|
||||
", ".join(self.publishers) if hasattr(self, "publishers") else None,
|
||||
]
|
||||
|
|
35
bookwyrm/models/series.py
Normal file
35
bookwyrm/models/series.py
Normal file
|
@ -0,0 +1,35 @@
|
|||
"""series of books"""
|
||||
|
||||
from django.db import models
|
||||
|
||||
from .base_model import BookWyrmModel
|
||||
from . import fields
|
||||
|
||||
|
||||
class Series(BookWyrmModel):
|
||||
"""a named series of books"""
|
||||
|
||||
name = fields.CharField(max_length=100)
|
||||
authors = fields.ManyToManyField("Author") # TODO: add on Author model
|
||||
books = fields.ManyToManyField(
|
||||
"Book",
|
||||
through="SeriesBook",
|
||||
through_fields=("series", "book"),
|
||||
related_name="series_books",
|
||||
)
|
||||
|
||||
|
||||
class SeriesBook(BookWyrmModel):
|
||||
"""membership of a series"""
|
||||
|
||||
book = models.ForeignKey("Book", on_delete=models.PROTECT)
|
||||
series = models.ForeignKey("Series", on_delete=models.PROTECT)
|
||||
number = fields.CharField(max_length=255, blank=True, null=True)
|
||||
|
||||
collection_field = "series"
|
||||
|
||||
class Meta:
|
||||
"""a series can't contain the same book twice"""
|
||||
|
||||
unique_together = ("book", "series")
|
||||
ordering = ["-number"]
|
|
@ -31,7 +31,7 @@
|
|||
{{ book.title }}
|
||||
</h1>
|
||||
|
||||
{% if book.subtitle or book.series %}
|
||||
{% if book.subtitle or book.series.exists %}
|
||||
<p class="subtitle title is-5">
|
||||
{% if book.subtitle %}
|
||||
<meta
|
||||
|
@ -44,20 +44,15 @@
|
|||
</span>
|
||||
{% endif %}
|
||||
|
||||
{% if book.series %}
|
||||
<meta itemprop="position" content="{{ book.series_number }}">
|
||||
{% for book_series in book.series.all %}
|
||||
<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 | urlencode }}"
|
||||
itemprop="url">
|
||||
{% endif %}
|
||||
<span itemprop="name">{{ book.series }}</span>
|
||||
{% if book.series_number %} #{{ book.series_number }}{% endif %}
|
||||
{% if book.authors.exists %}
|
||||
<meta itemprop="position" content="{{ book_series.number }}">
|
||||
<a href="{{ book_series.local_path }}" itemprop="url">
|
||||
<span itemprop="name">{{ book_series.series.name }}</span>
|
||||
</a>
|
||||
{% endif %}
|
||||
{% if book.series_number %} #{{ book.series_number }}{% endif %}
|
||||
</span>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</p>
|
||||
{% endif %}
|
||||
|
||||
|
|
Loading…
Reference in a new issue