mirror of
https://github.com/bookwyrm-social/bookwyrm.git
synced 2024-11-25 19:11:09 +00:00
Merge branch 'main' into query-time
This commit is contained in:
commit
d56a21e232
73 changed files with 122 additions and 136 deletions
58
.github/pull_request_template.md
vendored
58
.github/pull_request_template.md
vendored
|
@ -1,10 +1,5 @@
|
|||
<!--
|
||||
Thanks for contributing!
|
||||
|
||||
Please ensure the name of your PR is written in imperative present tense. For example:
|
||||
|
||||
- "fix color contrast on submit buttons"
|
||||
- "add 'favourite food' value to Author model"
|
||||
Thanks for contributing! This template has some checkboxes that help keep track of what changes go into a release.
|
||||
|
||||
To check (tick) a list item, replace the space between square brackets with an x, like this:
|
||||
|
||||
|
@ -12,24 +7,23 @@ To check (tick) a list item, replace the space between square brackets with an x
|
|||
|
||||
You can find more information and tips for BookWyrm contributors at https://docs.joinbookwyrm.com/contributing.html
|
||||
-->
|
||||
|
||||
## Are you finished?
|
||||
|
||||
### Linters
|
||||
## Description
|
||||
<!--
|
||||
Please run linters on your code before submitting your PR.
|
||||
If you miss this step it is likely that the GitHub task runners will fail.
|
||||
Describe what your pull request does here
|
||||
-->
|
||||
|
||||
- [ ] I have checked my code with `black`, `pylint`, and `mypy`, or `./bw-dev formatters`
|
||||
|
||||
### Tests
|
||||
<!-- Check one -->
|
||||
<!--
|
||||
For pull requests that relate or close an issue, please include them
|
||||
below. We like to follow [Github's guidance on linking issues to pull requests](https://docs.github.com/en/issues/tracking-your-work-with-issues/linking-a-pull-request-to-an-issue).
|
||||
|
||||
- [ ] My changes do not need new tests
|
||||
- [ ] All tests I have added are passing
|
||||
- [ ] I have written tests but need help to make them pass
|
||||
- [ ] I have not written tests and need help to write them
|
||||
For example having the text: "closes #1234" would connect the current pull
|
||||
request to issue 1234. And when we merge the pull request, Github will
|
||||
automatically close the issue.
|
||||
-->
|
||||
|
||||
- Related Issue #
|
||||
- Closes #
|
||||
|
||||
## What type of Pull Request is this?
|
||||
<!-- Check all that apply -->
|
||||
|
@ -48,21 +42,6 @@ If you miss this step it is likely that the GitHub task runners will fail.
|
|||
|
||||
### Details of breaking or configuration changes (if any of above checked)
|
||||
|
||||
## Description
|
||||
|
||||
<!--
|
||||
Describe what your pull request does here.
|
||||
|
||||
For pull requests that relate or close an issue, please include them
|
||||
below. We like to follow [Github's guidance on linking issues to pull requests](https://docs.github.com/en/issues/tracking-your-work-with-issues/linking-a-pull-request-to-an-issue).
|
||||
|
||||
For example having the text: "closes #1234" would connect the current pull
|
||||
request to issue 1234. And when we merge the pull request, Github will
|
||||
automatically close the issue.
|
||||
-->
|
||||
|
||||
- Related Issue #
|
||||
- Closes #
|
||||
|
||||
## Documentation
|
||||
<!--
|
||||
|
@ -76,3 +55,14 @@ Our documentation is maintained in a separate repository at https://github.com/b
|
|||
- [ ] I have created a matching pull request in the Documentation repository
|
||||
- [ ] I intend to create a matching pull request in the Documentation repository after this PR is merged
|
||||
|
||||
<!-- Amazing! Thanks for filling that out. Your PR will need to have passing tests and happy linters before we can merge
|
||||
You will need to check your code with `black`, `pylint`, and `mypy`, or `./bw-dev formatters`
|
||||
-->
|
||||
|
||||
### Tests
|
||||
<!-- Check one -->
|
||||
|
||||
- [ ] My changes do not need new tests
|
||||
- [ ] All tests I have added are passing
|
||||
- [ ] I have written tests but need help to make them pass
|
||||
- [ ] I have not written tests and need help to write them
|
||||
|
|
14
.pylintrc
14
.pylintrc
|
@ -3,7 +3,19 @@ ignore=migrations
|
|||
load-plugins=pylint.extensions.no_self_use
|
||||
|
||||
[MESSAGES CONTROL]
|
||||
disable=E1101,E1135,E1136,R0903,R0901,R0902,W0707,W0511,W0406,R0401,R0801,C3001,import-error
|
||||
disable =
|
||||
cyclic-import,
|
||||
duplicate-code,
|
||||
fixme,
|
||||
no-member,
|
||||
raise-missing-from,
|
||||
too-few-public-methods,
|
||||
too-many-ancestors,
|
||||
too-many-instance-attributes,
|
||||
unnecessary-lambda-assignment,
|
||||
unsubscriptable-object,
|
||||
enable =
|
||||
useless-suppression
|
||||
|
||||
[FORMAT]
|
||||
max-line-length=88
|
||||
|
|
|
@ -67,7 +67,6 @@ class Edition(Book):
|
|||
type: str = "Edition"
|
||||
|
||||
|
||||
# pylint: disable=invalid-name
|
||||
@dataclass(init=False)
|
||||
class Work(Book):
|
||||
"""work instance of a book object"""
|
||||
|
|
|
@ -18,7 +18,6 @@ class OrderedCollection(ActivityObject):
|
|||
type: str = "OrderedCollection"
|
||||
|
||||
|
||||
# pylint: disable=invalid-name
|
||||
@dataclass(init=False)
|
||||
class OrderedCollectionPrivate(OrderedCollection):
|
||||
"""an ordered collection with privacy settings"""
|
||||
|
|
|
@ -22,7 +22,6 @@ class Verb(ActivityObject):
|
|||
self.object.to_model(allow_external_connections=allow_external_connections)
|
||||
|
||||
|
||||
# pylint: disable=invalid-name
|
||||
@dataclass(init=False)
|
||||
class Create(Verb):
|
||||
"""Create activity"""
|
||||
|
@ -33,7 +32,6 @@ class Create(Verb):
|
|||
type: str = "Create"
|
||||
|
||||
|
||||
# pylint: disable=invalid-name
|
||||
@dataclass(init=False)
|
||||
class Delete(Verb):
|
||||
"""Create activity"""
|
||||
|
@ -63,7 +61,6 @@ class Delete(Verb):
|
|||
# if we can't find it, we don't need to delete it because we don't have it
|
||||
|
||||
|
||||
# pylint: disable=invalid-name
|
||||
@dataclass(init=False)
|
||||
class Update(Verb):
|
||||
"""Update activity"""
|
||||
|
@ -227,7 +224,6 @@ class Like(Verb):
|
|||
self.to_model(allow_external_connections=allow_external_connections)
|
||||
|
||||
|
||||
# pylint: disable=invalid-name
|
||||
@dataclass(init=False)
|
||||
class Announce(Verb):
|
||||
"""boosting a status"""
|
||||
|
|
|
@ -32,7 +32,7 @@ class ActivityStream(RedisStore):
|
|||
stream_id = self.stream_id(user_id)
|
||||
return f"{stream_id}-unread-by-type"
|
||||
|
||||
def get_rank(self, obj): # pylint: disable=no-self-use
|
||||
def get_rank(self, obj):
|
||||
"""statuses are sorted by date published"""
|
||||
return obj.published_date.timestamp()
|
||||
|
||||
|
|
|
@ -33,7 +33,6 @@ class BookwyrmConfig(AppConfig):
|
|||
name = "bookwyrm"
|
||||
verbose_name = "BookWyrm"
|
||||
|
||||
# pylint: disable=no-self-use
|
||||
def ready(self):
|
||||
"""set up OTLP and preview image files, if desired"""
|
||||
if settings.OTEL_EXPORTER_OTLP_ENDPOINT or settings.OTEL_EXPORTER_CONSOLE:
|
||||
|
|
|
@ -36,7 +36,6 @@ def search(
|
|||
...
|
||||
|
||||
|
||||
# pylint: disable=arguments-differ
|
||||
def search(
|
||||
query: str,
|
||||
*,
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
from bookwyrm import models, settings
|
||||
|
||||
|
||||
def site_settings(request): # pylint: disable=unused-argument
|
||||
def site_settings(request):
|
||||
"""include the custom info about the site"""
|
||||
request_protocol = "https://"
|
||||
if not request.is_secure():
|
||||
|
|
|
@ -15,9 +15,9 @@ class StyledForm(ModelForm):
|
|||
css_classes["number"] = "input"
|
||||
css_classes["checkbox"] = "checkbox"
|
||||
css_classes["textarea"] = "textarea"
|
||||
# pylint: disable=super-with-arguments
|
||||
super().__init__(*args, **kwargs)
|
||||
for visible in self.visible_fields():
|
||||
input_type = ""
|
||||
if hasattr(visible.field.widget, "input_type"):
|
||||
input_type = visible.field.widget.input_type
|
||||
if isinstance(visible.field.widget, Textarea):
|
||||
|
|
|
@ -34,7 +34,6 @@ class LoginForm(CustomForm):
|
|||
|
||||
def add_invalid_password_error(self):
|
||||
"""We don't want to be too specific about this"""
|
||||
# pylint: disable=attribute-defined-outside-init
|
||||
self.non_field_errors = _("Username or password are incorrect")
|
||||
|
||||
|
||||
|
|
|
@ -5,8 +5,6 @@ from django import forms
|
|||
class ArrayWidget(forms.widgets.TextInput):
|
||||
"""Inputs for postgres array fields"""
|
||||
|
||||
# pylint: disable=unused-argument
|
||||
# pylint: disable=no-self-use
|
||||
def value_from_datadict(self, data, files, name):
|
||||
"""get all values for this name"""
|
||||
return [i for i in data.getlist(name) if i]
|
||||
|
|
|
@ -36,7 +36,6 @@ class Importer:
|
|||
"reading": ["currently-reading", "reading", "currently reading"],
|
||||
}
|
||||
|
||||
# pylint: disable=too-many-locals
|
||||
def create_job(
|
||||
self, user: User, csv_file: Iterable[str], include_reviews: bool, privacy: str
|
||||
) -> ImportJob:
|
||||
|
|
|
@ -20,7 +20,7 @@ class LibrarythingImporter(Importer):
|
|||
|
||||
def normalize_row(
|
||||
self, entry: dict[str, str], mappings: dict[str, Optional[str]]
|
||||
) -> dict[str, Optional[str]]: # pylint: disable=no-self-use
|
||||
) -> dict[str, Optional[str]]:
|
||||
"""use the dataclass to create the formatted row of data"""
|
||||
normalized = {
|
||||
k: _remove_brackets(entry.get(v) if v else None)
|
||||
|
|
|
@ -18,7 +18,7 @@ class ListsStream(RedisStore):
|
|||
return f"{user}-lists"
|
||||
return f"{user.id}-lists"
|
||||
|
||||
def get_rank(self, obj): # pylint: disable=no-self-use
|
||||
def get_rank(self, obj):
|
||||
"""lists are sorted by updated date"""
|
||||
return obj.updated_date.timestamp()
|
||||
|
||||
|
|
|
@ -31,7 +31,7 @@ logger = logging.getLogger(__name__)
|
|||
|
||||
PropertyField = namedtuple("PropertyField", ("set_activity_from_field"))
|
||||
|
||||
# pylint: disable=invalid-name
|
||||
|
||||
def set_activity_from_property_field(activity, obj, field):
|
||||
"""assign a model property value to the activity json"""
|
||||
activity[field[1]] = getattr(obj, field[0])
|
||||
|
|
|
@ -133,7 +133,6 @@ class BookDataModel(ObjectMixin, BookWyrmModel):
|
|||
related_models = [
|
||||
(r.remote_field.name, r.related_model) for r in self._meta.related_objects
|
||||
]
|
||||
# pylint: disable=protected-access
|
||||
for related_field, related_model in related_models:
|
||||
# Skip the ManyToMany fields that aren’t auto-created. These
|
||||
# should have a corresponding OneToMany field in the model for
|
||||
|
|
|
@ -27,7 +27,7 @@ logger = logging.getLogger(__name__)
|
|||
class BookwyrmAwsSession(BotoSession):
|
||||
"""a boto session that always uses settings.AWS_S3_ENDPOINT_URL"""
|
||||
|
||||
def client(self, *args, **kwargs): # pylint: disable=arguments-differ
|
||||
def client(self, *args, **kwargs):
|
||||
kwargs["endpoint_url"] = settings.AWS_S3_ENDPOINT_URL
|
||||
return super().client("s3", *args, **kwargs)
|
||||
|
||||
|
|
|
@ -193,8 +193,7 @@ class UsernameField(ActivitypubFieldMixin, models.CharField):
|
|||
|
||||
def __init__(self, activitypub_field="preferredUsername", **kwargs):
|
||||
self.activitypub_field = activitypub_field
|
||||
# I don't totally know why pylint is mad at this, but it makes it work
|
||||
super(ActivitypubFieldMixin, self).__init__( # pylint: disable=bad-super-call
|
||||
super(ActivitypubFieldMixin, self).__init__(
|
||||
_("username"),
|
||||
max_length=150,
|
||||
unique=True,
|
||||
|
@ -234,7 +233,6 @@ class PrivacyField(ActivitypubFieldMixin, models.CharField):
|
|||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, max_length=255, choices=PrivacyLevels, default="public")
|
||||
|
||||
# pylint: disable=invalid-name
|
||||
def set_field_from_activity(
|
||||
self, instance, data, overwrite=True, allow_external_connections=True
|
||||
):
|
||||
|
@ -276,7 +274,6 @@ class PrivacyField(ActivitypubFieldMixin, models.CharField):
|
|||
if hasattr(instance, "mention_users"):
|
||||
mentions = [u.remote_id for u in instance.mention_users.all()]
|
||||
# this is a link to the followers list
|
||||
# pylint: disable=protected-access
|
||||
followers = instance.user.followers_url
|
||||
if instance.privacy == "public":
|
||||
activity["to"] = [self.public]
|
||||
|
@ -444,7 +441,7 @@ class ImageField(ActivitypubFieldMixin, models.ImageField):
|
|||
self.alt_field = alt_field
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
# pylint: disable=arguments-differ,arguments-renamed,too-many-arguments
|
||||
# pylint: disable=arguments-renamed,too-many-arguments
|
||||
def set_field_from_activity(
|
||||
self, instance, data, save=True, overwrite=True, allow_external_connections=True
|
||||
):
|
||||
|
|
|
@ -352,7 +352,7 @@ def import_item_task(item_id):
|
|||
|
||||
try:
|
||||
item.resolve()
|
||||
except Exception as err: # pylint: disable=broad-except
|
||||
except Exception as err:
|
||||
item.fail_reason = _("Error loading book")
|
||||
item.save()
|
||||
item.update_job()
|
||||
|
|
|
@ -135,7 +135,7 @@ class UserFollowRequest(ActivitypubMixin, UserRelationship):
|
|||
status = "follow_request"
|
||||
activity_serializer = activitypub.Follow
|
||||
|
||||
def save(self, *args, broadcast=True, **kwargs): # pylint: disable=arguments-differ
|
||||
def save(self, *args, broadcast=True, **kwargs):
|
||||
"""make sure the follow or block relationship doesn't already exist"""
|
||||
# if there's a request for a follow that already exists, accept it
|
||||
# without changing the local database state
|
||||
|
|
|
@ -98,7 +98,7 @@ class Status(OrderedCollectionPageMixin, BookWyrmModel):
|
|||
self.thread_id = self.id
|
||||
super().save(broadcast=False, update_fields=["thread_id"])
|
||||
|
||||
def delete(self, *args, **kwargs): # pylint: disable=unused-argument
|
||||
def delete(self, *args, **kwargs):
|
||||
""" "delete" a status"""
|
||||
if hasattr(self, "boosted_status"):
|
||||
# okay but if it's a boost really delete it
|
||||
|
@ -213,7 +213,7 @@ class Status(OrderedCollectionPageMixin, BookWyrmModel):
|
|||
**kwargs,
|
||||
).serialize()
|
||||
|
||||
def to_activity_dataclass(self, pure=False): # pylint: disable=arguments-differ
|
||||
def to_activity_dataclass(self, pure=False):
|
||||
"""return tombstone if the status is deleted"""
|
||||
if self.deleted:
|
||||
return activitypub.Tombstone(
|
||||
|
|
|
@ -409,7 +409,6 @@ class User(OrderedCollectionPageMixin, AbstractUser):
|
|||
|
||||
def delete(self, *args, **kwargs):
|
||||
"""We don't actually delete the database entry"""
|
||||
# pylint: disable=attribute-defined-outside-init
|
||||
self.is_active = False
|
||||
self.allow_reactivation = False
|
||||
self.is_deleted = True
|
||||
|
@ -452,7 +451,6 @@ class User(OrderedCollectionPageMixin, AbstractUser):
|
|||
|
||||
def deactivate(self):
|
||||
"""Disable the user but allow them to reactivate"""
|
||||
# pylint: disable=attribute-defined-outside-init
|
||||
self.is_active = False
|
||||
self.deactivation_reason = "self_deactivation"
|
||||
self.allow_reactivation = True
|
||||
|
@ -460,7 +458,6 @@ class User(OrderedCollectionPageMixin, AbstractUser):
|
|||
|
||||
def reactivate(self):
|
||||
"""Now you want to come back, huh?"""
|
||||
# pylint: disable=attribute-defined-outside-init
|
||||
if not self.allow_reactivation:
|
||||
return
|
||||
self.is_active = True
|
||||
|
|
|
@ -420,7 +420,6 @@ def save_and_cleanup(image, instance=None):
|
|||
return True
|
||||
|
||||
|
||||
# pylint: disable=invalid-name
|
||||
@app.task(queue=IMAGES)
|
||||
def generate_site_preview_image_task():
|
||||
"""generate preview_image for the website"""
|
||||
|
@ -445,7 +444,6 @@ def generate_site_preview_image_task():
|
|||
save_and_cleanup(image, instance=site)
|
||||
|
||||
|
||||
# pylint: disable=invalid-name
|
||||
@app.task(queue=IMAGES)
|
||||
def generate_edition_preview_image_task(book_id):
|
||||
"""generate preview_image for a book"""
|
||||
|
|
|
@ -6,7 +6,7 @@ from base64 import b64encode, b64decode
|
|||
|
||||
from Crypto import Random
|
||||
from Crypto.PublicKey import RSA
|
||||
from Crypto.Signature import pkcs1_15 # pylint: disable=no-name-in-module
|
||||
from Crypto.Signature import pkcs1_15
|
||||
from Crypto.Hash import SHA256
|
||||
|
||||
MAX_SIGNATURE_AGE = 300
|
||||
|
@ -84,7 +84,6 @@ class Signature:
|
|||
self.headers = headers
|
||||
self.signature = signature
|
||||
|
||||
# pylint: disable=invalid-name
|
||||
@classmethod
|
||||
def parse(cls, request):
|
||||
"""extract and parse a signature from an http request"""
|
||||
|
|
|
@ -34,7 +34,6 @@ class SuggestedUsers(RedisStore):
|
|||
|
||||
def get_counts_from_rank(self, rank): # pylint: disable=no-self-use
|
||||
"""calculate mutuals count and shared books count from rank"""
|
||||
# pylint: disable=c-extension-no-member
|
||||
return {
|
||||
"mutuals": math.floor(rank),
|
||||
# "shared_books": int(1 / (-1 * (rank % 1 - 1))) - 1,
|
||||
|
@ -128,7 +127,6 @@ def get_annotated_users(viewer, *args, **kwargs):
|
|||
),
|
||||
distinct=True,
|
||||
),
|
||||
# pylint: disable=line-too-long
|
||||
# shared_books=Count(
|
||||
# "shelfbook",
|
||||
# filter=Q(
|
||||
|
@ -202,7 +200,7 @@ def update_suggestions_on_unfollow(sender, instance, **kwargs):
|
|||
|
||||
|
||||
@receiver(signals.post_save, sender=models.User)
|
||||
# pylint: disable=unused-argument, too-many-arguments
|
||||
# pylint: disable=unused-argument
|
||||
def update_user(sender, instance, created, update_fields=None, **kwargs):
|
||||
"""an updated user, neat"""
|
||||
# a new user is found, create suggestions for them
|
||||
|
|
|
@ -3,8 +3,10 @@
|
|||
{% load utilities %}
|
||||
|
||||
{% block heading %}
|
||||
{% block title %}
|
||||
{% blocktrans with username=user.localname sitename=site.name %}Follow {{ username }} on the fediverse{% endblocktrans %}
|
||||
{% endblock %}
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="block card">
|
||||
|
|
|
@ -2,6 +2,10 @@
|
|||
{% load i18n %}
|
||||
{% load utilities %}
|
||||
|
||||
{% block title %}
|
||||
{% blocktrans with display_name=user.display_name %}You are now following {{ display_name }}!{% endblocktrans %}
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="block card">
|
||||
<div class="card-content">
|
||||
|
|
|
@ -115,7 +115,6 @@ class AbstractConnector(TestCase):
|
|||
@responses.activate
|
||||
def test_get_or_create_author(self):
|
||||
"""load an author"""
|
||||
# pylint: disable=attribute-defined-outside-init
|
||||
self.connector.author_mappings = [
|
||||
Mapping("id"),
|
||||
Mapping("name"),
|
||||
|
@ -141,7 +140,6 @@ class AbstractConnector(TestCase):
|
|||
def test_update_author_from_remote(self):
|
||||
"""trigger the function that looks up the remote data"""
|
||||
author = models.Author.objects.create(name="Test", openlibrary_key="OL123A")
|
||||
# pylint: disable=attribute-defined-outside-init
|
||||
self.connector.author_mappings = [
|
||||
Mapping("id"),
|
||||
Mapping("name"),
|
||||
|
|
|
@ -20,7 +20,7 @@ from bookwyrm.models.activitypub_mixin import (
|
|||
from bookwyrm.settings import PAGE_LENGTH
|
||||
|
||||
|
||||
# pylint: disable=invalid-name,too-many-public-methods
|
||||
# pylint: disable=too-many-public-methods
|
||||
@patch("bookwyrm.activitystreams.add_status_task.delay")
|
||||
@patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async")
|
||||
class ActivitypubMixins(TestCase):
|
||||
|
|
|
@ -42,7 +42,7 @@ class BaseModel(TestCase):
|
|||
|
||||
def test_remote_id(self):
|
||||
"""these should be generated"""
|
||||
self.test_model.id = 1 # pylint: disable=invalid-name
|
||||
self.test_model.id = 1
|
||||
expected = self.test_model.get_remote_id()
|
||||
self.assertEqual(expected, f"{BASE_URL}/bookwyrmtestmodel/1")
|
||||
|
||||
|
|
|
@ -13,7 +13,7 @@ from bookwyrm.utils.tar import BookwyrmTarFile
|
|||
from bookwyrm.models import bookwyrm_import_job
|
||||
|
||||
|
||||
class BookwyrmImport(TestCase): # pylint: disable=too-many-public-methods
|
||||
class BookwyrmImport(TestCase):
|
||||
"""testing user import functions"""
|
||||
|
||||
def setUp(self):
|
||||
|
|
|
@ -6,7 +6,6 @@ from django.test import TestCase
|
|||
from bookwyrm import models, settings
|
||||
|
||||
|
||||
# pylint: disable=unused-argument
|
||||
@patch("bookwyrm.suggested_users.rerank_suggestions_task.delay")
|
||||
@patch("bookwyrm.activitystreams.populate_stream_task.delay")
|
||||
@patch("bookwyrm.lists_stream.populate_lists_task.delay")
|
||||
|
|
|
@ -10,7 +10,7 @@ class MergeBookDataModel(TestCase):
|
|||
"""test merging of subclasses of BookDataModel"""
|
||||
|
||||
@classmethod
|
||||
def setUpTestData(cls): # pylint: disable=invalid-name
|
||||
def setUpTestData(cls):
|
||||
"""shared data"""
|
||||
models.SiteSettings.objects.create()
|
||||
|
||||
|
|
|
@ -42,7 +42,7 @@ def validate_html(html):
|
|||
validator.feed(str(html.content))
|
||||
|
||||
|
||||
class HtmlValidator(HTMLParser): # pylint: disable=abstract-method
|
||||
class HtmlValidator(HTMLParser):
|
||||
"""Checks for custom html validation requirements"""
|
||||
|
||||
def __init__(self):
|
||||
|
|
|
@ -14,7 +14,6 @@ from bookwyrm.tests.validate_html import validate_html
|
|||
class ImportUserViews(TestCase):
|
||||
"""user import views"""
|
||||
|
||||
# pylint: disable=invalid-name
|
||||
def setUp(self):
|
||||
"""we need basic test data and mocks"""
|
||||
self.factory = RequestFactory()
|
||||
|
|
|
@ -11,7 +11,6 @@ from django.test.client import RequestFactory
|
|||
from bookwyrm import models, views
|
||||
|
||||
|
||||
# pylint: disable=too-many-public-methods
|
||||
class Inbox(TestCase):
|
||||
"""readthrough tests"""
|
||||
|
||||
|
|
|
@ -7,7 +7,6 @@ import responses
|
|||
from bookwyrm import models, views
|
||||
|
||||
|
||||
# pylint: disable=too-many-public-methods
|
||||
class InboxAdd(TestCase):
|
||||
"""inbox tests"""
|
||||
|
||||
|
|
|
@ -7,7 +7,6 @@ import responses
|
|||
from bookwyrm import models, views
|
||||
|
||||
|
||||
# pylint: disable=too-many-public-methods
|
||||
class InboxActivities(TestCase):
|
||||
"""inbox tests"""
|
||||
|
||||
|
|
|
@ -6,7 +6,6 @@ from django.test import TestCase
|
|||
from bookwyrm import models, views
|
||||
|
||||
|
||||
# pylint: disable=too-many-public-methods
|
||||
class InboxBlock(TestCase):
|
||||
"""inbox tests"""
|
||||
|
||||
|
|
|
@ -9,7 +9,6 @@ from bookwyrm import models, views
|
|||
from bookwyrm.activitypub import ActivitySerializerError
|
||||
|
||||
|
||||
# pylint: disable=too-many-public-methods
|
||||
class TransactionInboxCreate(TransactionTestCase):
|
||||
"""readthrough tests"""
|
||||
|
||||
|
|
|
@ -7,7 +7,6 @@ from django.test import TestCase
|
|||
from bookwyrm import models, views
|
||||
|
||||
|
||||
# pylint: disable=too-many-public-methods
|
||||
class InboxActivities(TestCase):
|
||||
"""inbox tests"""
|
||||
|
||||
|
|
|
@ -7,7 +7,6 @@ from django.test import TestCase
|
|||
from bookwyrm import models, views
|
||||
|
||||
|
||||
# pylint: disable=too-many-public-methods
|
||||
class InboxRelationships(TestCase):
|
||||
"""inbox tests"""
|
||||
|
||||
|
|
|
@ -6,7 +6,6 @@ from django.test import TestCase
|
|||
from bookwyrm import models, views
|
||||
|
||||
|
||||
# pylint: disable=too-many-public-methods
|
||||
class InboxActivities(TestCase):
|
||||
"""inbox tests"""
|
||||
|
||||
|
|
|
@ -6,7 +6,6 @@ from django.test import TestCase
|
|||
from bookwyrm import models, views
|
||||
|
||||
|
||||
# pylint: disable=too-many-public-methods
|
||||
class InboxRemove(TestCase):
|
||||
"""inbox tests"""
|
||||
|
||||
|
|
|
@ -8,7 +8,6 @@ from django.test import TestCase
|
|||
from bookwyrm import models, views
|
||||
|
||||
|
||||
# pylint: disable=too-many-public-methods
|
||||
class InboxUpdate(TestCase):
|
||||
"""inbox tests"""
|
||||
|
||||
|
@ -161,7 +160,6 @@ class InboxUpdate(TestCase):
|
|||
datafile = pathlib.Path(__file__).parent.joinpath("../../data/bw_edition.json")
|
||||
bookdata = json.loads(datafile.read_bytes())
|
||||
del bookdata["authors"]
|
||||
# pylint: disable=line-too-long
|
||||
link_data = {
|
||||
"href": "https://openlibrary.org/books/OL11645413M/Queen_Victoria/daisy",
|
||||
"mediaType": "Daisy",
|
||||
|
|
|
@ -11,7 +11,6 @@ from bookwyrm import forms, models, views
|
|||
from bookwyrm.tests.validate_html import validate_html
|
||||
|
||||
|
||||
# pylint: disable=too-many-public-methods
|
||||
@patch("bookwyrm.suggested_users.rerank_suggestions_task.delay")
|
||||
@patch("bookwyrm.activitystreams.populate_stream_task.delay")
|
||||
class LoginViews(TestCase):
|
||||
|
|
|
@ -11,7 +11,6 @@ from bookwyrm import models, views
|
|||
from bookwyrm.tests.validate_html import validate_html
|
||||
|
||||
|
||||
# pylint: disable=unused-argument
|
||||
class ListViews(TestCase):
|
||||
"""list view"""
|
||||
|
||||
|
|
|
@ -11,7 +11,6 @@ from bookwyrm import models, views
|
|||
from bookwyrm.tests.validate_html import validate_html
|
||||
|
||||
|
||||
# pylint: disable=unused-argument
|
||||
class ListViews(TestCase):
|
||||
"""list view"""
|
||||
|
||||
|
|
|
@ -13,7 +13,6 @@ from bookwyrm.activitypub import ActivitypubResponse
|
|||
from bookwyrm.tests.validate_html import validate_html
|
||||
|
||||
|
||||
# pylint: disable=unused-argument
|
||||
# pylint: disable=too-many-public-methods
|
||||
class ListViews(TestCase):
|
||||
"""list view"""
|
||||
|
|
|
@ -7,8 +7,6 @@ from django.test.client import RequestFactory
|
|||
from bookwyrm import models, views
|
||||
|
||||
|
||||
# pylint: disable=unused-argument
|
||||
# pylint: disable=too-many-public-methods
|
||||
class ListItemViews(TestCase):
|
||||
"""list view"""
|
||||
|
||||
|
|
|
@ -11,7 +11,7 @@ from django.test.client import RequestFactory
|
|||
from bookwyrm import models, views
|
||||
from bookwyrm.tests.validate_html import validate_html
|
||||
|
||||
# pylint: disable=unused-argument
|
||||
|
||||
class ListViews(TestCase):
|
||||
"""lists of lists"""
|
||||
|
||||
|
|
|
@ -18,7 +18,7 @@ class ExportViews(TestCase):
|
|||
"""viewing and creating statuses"""
|
||||
|
||||
@classmethod
|
||||
def setUpTestData(cls): # pylint: disable=invalid-name
|
||||
def setUpTestData(cls):
|
||||
"""we need basic test data and mocks"""
|
||||
with (
|
||||
patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"),
|
||||
|
@ -41,7 +41,6 @@ class ExportViews(TestCase):
|
|||
bnf_id="beep",
|
||||
)
|
||||
|
||||
# pylint: disable=invalid-name
|
||||
def setUp(self):
|
||||
"""individual test setup"""
|
||||
self.factory = RequestFactory()
|
||||
|
|
|
@ -11,7 +11,7 @@ from django.test.client import RequestFactory
|
|||
|
||||
from bookwyrm import forms, models, views
|
||||
|
||||
# pylint: disable=too-many-public-methods
|
||||
|
||||
@patch("bookwyrm.suggested_users.rerank_suggestions_task.delay")
|
||||
@patch("bookwyrm.activitystreams.populate_stream_task.delay")
|
||||
class TwoFactorViews(TestCase):
|
||||
|
|
|
@ -9,7 +9,7 @@ from django.test.client import RequestFactory
|
|||
from bookwyrm import models, views
|
||||
from bookwyrm.tests.validate_html import validate_html
|
||||
|
||||
# pylint: disable=unused-argument
|
||||
|
||||
class DirectoryViews(TestCase):
|
||||
"""tag views"""
|
||||
|
||||
|
|
|
@ -10,7 +10,6 @@ from bookwyrm import models, views
|
|||
from bookwyrm.settings import USER_AGENT
|
||||
|
||||
|
||||
# pylint: disable=too-many-public-methods
|
||||
@patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async")
|
||||
class OutboxView(TestCase):
|
||||
"""sends out activities"""
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
""" test for app action functionality """
|
||||
import json
|
||||
from unittest.mock import patch
|
||||
import dateutil
|
||||
from django.core.exceptions import PermissionDenied
|
||||
from django.test import TestCase, TransactionTestCase
|
||||
from django.test.client import RequestFactory
|
||||
from django.utils import timezone
|
||||
|
||||
from bookwyrm import forms, models, views
|
||||
from bookwyrm.views.status import find_mentions, find_or_create_hashtags
|
||||
|
@ -167,6 +169,37 @@ class StatusViews(TestCase):
|
|||
self.assertEqual(status.rating, 4.0)
|
||||
self.assertIsNone(status.edited_date)
|
||||
|
||||
def test_create_status_progress(self, *_):
|
||||
"""create a status that updates a readthrough"""
|
||||
start_date = timezone.make_aware(dateutil.parser.parse("2024-07-27"))
|
||||
readthrough = models.ReadThrough.objects.create(
|
||||
book=self.book, user=self.local_user, start_date=start_date
|
||||
)
|
||||
|
||||
self.assertEqual(start_date, readthrough.start_date)
|
||||
self.assertIsNone(readthrough.progress)
|
||||
|
||||
view = views.CreateStatus.as_view()
|
||||
form = forms.CommentForm(
|
||||
{
|
||||
"progress": 1,
|
||||
"progress_mode": "PG",
|
||||
"content": "I started the book",
|
||||
"id": readthrough.id,
|
||||
"book": self.book.id,
|
||||
"user": self.local_user.id,
|
||||
"privacy": "public",
|
||||
}
|
||||
)
|
||||
request = self.factory.post("", form.data)
|
||||
request.user = self.local_user
|
||||
|
||||
view(request, "comment")
|
||||
readthrough.refresh_from_db()
|
||||
|
||||
self.assertEqual(1, readthrough.progress)
|
||||
self.assertEqual(start_date, readthrough.start_date) # not overwritten
|
||||
|
||||
def test_create_status_wrong_user(self, *_):
|
||||
"""You can't compose statuses for someone else"""
|
||||
view = views.CreateStatus.as_view()
|
||||
|
|
|
@ -52,7 +52,6 @@ class PartialDate(datetime):
|
|||
Use subclasses to specify precision. If `dt` is naive, `ValueError`
|
||||
is raised.
|
||||
"""
|
||||
# pylint: disable=invalid-name
|
||||
if timezone.is_naive(dt):
|
||||
raise ValueError("naive datetime not accepted")
|
||||
return cls.combine(dt.date(), dt.time(), tzinfo=dt.tzinfo)
|
||||
|
|
|
@ -88,6 +88,7 @@ class CeleryStatus(View):
|
|||
def post(self, request):
|
||||
"""Submit form to clear queues"""
|
||||
form = ClearCeleryForm(request.POST)
|
||||
results = []
|
||||
if form.is_valid():
|
||||
if len(celery.control.ping()) != 0:
|
||||
return HttpResponse(
|
||||
|
|
|
@ -43,7 +43,6 @@ class Dashboard(View):
|
|||
) or not re.match(regex.DOMAIN, settings.EMAIL_SENDER_DOMAIN)
|
||||
|
||||
data["email_config_error"] = email_config_error
|
||||
# pylint: disable=line-too-long
|
||||
data[
|
||||
"email_sender"
|
||||
] = f"{settings.EMAIL_SENDER_NAME}@{settings.EMAIL_SENDER_DOMAIN}"
|
||||
|
|
|
@ -152,7 +152,7 @@ class FederatedServer(View):
|
|||
}
|
||||
return TemplateResponse(request, "settings/federation/instance.html", data)
|
||||
|
||||
def post(self, request, server): # pylint: disable=unused-argument
|
||||
def post(self, request, server):
|
||||
"""update note"""
|
||||
server = get_object_or_404(models.FederatedServer, id=server)
|
||||
server.notes = request.POST.get("notes")
|
||||
|
|
|
@ -63,7 +63,6 @@ class ImportList(View):
|
|||
}
|
||||
return TemplateResponse(request, "settings/imports/imports.html", data)
|
||||
|
||||
# pylint: disable=unused-argument
|
||||
def post(self, request, import_id):
|
||||
"""Mark an import as complete"""
|
||||
import_job = get_object_or_404(models.ImportJob, id=import_id)
|
||||
|
@ -95,7 +94,6 @@ def enable_imports(request):
|
|||
|
||||
@require_POST
|
||||
@permission_required("bookwyrm.edit_instance_settings", raise_exception=True)
|
||||
# pylint: disable=unused-argument
|
||||
def set_import_size_limit(request):
|
||||
"""Limit the amount of books users can import at once"""
|
||||
site = models.SiteSettings.objects.get()
|
||||
|
@ -120,7 +118,6 @@ def set_user_import_completed(request, import_id):
|
|||
|
||||
@require_POST
|
||||
@permission_required("bookwyrm.edit_instance_settings", raise_exception=True)
|
||||
# pylint: disable=unused-argument
|
||||
def set_user_import_limit(request):
|
||||
"""Limit how ofter users can import and export their account"""
|
||||
site = models.SiteSettings.objects.get()
|
||||
|
|
|
@ -204,7 +204,6 @@ def resolve_book(request):
|
|||
@login_required
|
||||
@require_POST
|
||||
@permission_required("bookwyrm.edit_book", raise_exception=True)
|
||||
# pylint: disable=unused-argument
|
||||
def update_book_from_remote(request, book_id, connector_identifier):
|
||||
"""load the remote data for this book"""
|
||||
connector = connector_manager.load_connector(
|
||||
|
|
|
@ -88,7 +88,6 @@ class CreateBook(View):
|
|||
data = {"form": forms.EditionForm()}
|
||||
return TemplateResponse(request, "book/edit/edit_book.html", data)
|
||||
|
||||
# pylint: disable=too-many-locals
|
||||
def post(self, request):
|
||||
"""create a new book"""
|
||||
# returns None if no match is found
|
||||
|
|
|
@ -240,7 +240,7 @@ def redirect_to_referer(request, *args, **kwargs):
|
|||
return redirect(*args or "/", **kwargs)
|
||||
|
||||
|
||||
# pylint: disable=redefined-builtin,invalid-name
|
||||
# pylint: disable=redefined-builtin
|
||||
def get_mergeable_object_or_404(klass, id):
|
||||
"""variant of get_object_or_404 that also redirects if id has been merged
|
||||
into another object"""
|
||||
|
|
|
@ -97,7 +97,7 @@ class Register(View):
|
|||
class ConfirmEmailCode(View):
|
||||
"""confirm email address"""
|
||||
|
||||
def get(self, request, code): # pylint: disable=unused-argument
|
||||
def get(self, request, code):
|
||||
"""you got the code! good work"""
|
||||
settings = models.SiteSettings.get()
|
||||
if request.user.is_authenticated:
|
||||
|
@ -124,7 +124,7 @@ class ConfirmEmailCode(View):
|
|||
class ConfirmEmail(View):
|
||||
"""enter code to confirm email address"""
|
||||
|
||||
def get(self, request): # pylint: disable=unused-argument
|
||||
def get(self, request):
|
||||
"""you need a code! keep looking"""
|
||||
settings = models.SiteSettings.get()
|
||||
if request.user.is_authenticated or not settings.require_confirm_email:
|
||||
|
|
|
@ -22,7 +22,6 @@ logger = logging.getLogger(__name__)
|
|||
|
||||
|
||||
# pylint: disable=no-self-use
|
||||
# pylint: disable=too-many-return-statements
|
||||
@method_decorator(login_required, name="dispatch")
|
||||
class ReadingStatus(View):
|
||||
"""consider reading a book"""
|
||||
|
|
|
@ -7,7 +7,7 @@ from ..models import Review, Quotation, Comment
|
|||
|
||||
from .helpers import get_user_from_username
|
||||
|
||||
# pylint: disable=no-self-use, unused-argument
|
||||
# pylint: disable=no-self-use
|
||||
class RssFeed(Feed):
|
||||
"""serialize user's posts in rss feed"""
|
||||
|
||||
|
|
|
@ -119,7 +119,6 @@ class Shelf(View):
|
|||
return TemplateResponse(request, "shelf/shelf.html", data)
|
||||
|
||||
@method_decorator(login_required, name="dispatch")
|
||||
# pylint: disable=unused-argument
|
||||
def post(self, request, username, shelf_identifier):
|
||||
"""edit a shelf"""
|
||||
user = get_user_from_username(request.user, username)
|
||||
|
|
|
@ -32,7 +32,7 @@ logger = logging.getLogger(__name__)
|
|||
class EditStatus(View):
|
||||
"""the view for *posting*"""
|
||||
|
||||
def get(self, request, status_id): # pylint: disable=unused-argument
|
||||
def get(self, request, status_id):
|
||||
"""load the edit panel"""
|
||||
status = get_object_or_404(
|
||||
models.Status.objects.select_subclasses(), id=status_id
|
||||
|
@ -201,12 +201,11 @@ def edit_readthrough(request):
|
|||
# TODO: remove this, it duplicates the code in the ReadThrough view
|
||||
readthrough = get_object_or_404(models.ReadThrough, id=request.POST.get("id"))
|
||||
|
||||
readthrough.start_date = load_date_in_user_tz_as_utc(
|
||||
request.POST.get("start_date"), request.user
|
||||
)
|
||||
readthrough.finish_date = load_date_in_user_tz_as_utc(
|
||||
request.POST.get("finish_date"), request.user
|
||||
)
|
||||
if start_date := request.POST.get("start_date"):
|
||||
readthrough.start_date = load_date_in_user_tz_as_utc(start_date, request.user)
|
||||
|
||||
if finish_date := request.POST.get("finish_date"):
|
||||
readthrough.finish_date = load_date_in_user_tz_as_utc(finish_date, request.user)
|
||||
|
||||
progress = request.POST.get("progress")
|
||||
try:
|
||||
|
|
|
@ -15,8 +15,12 @@ REDIS_BROKER_URL = env(
|
|||
f"redis://:{REDIS_BROKER_PASSWORD}@{REDIS_BROKER_HOST}:{REDIS_BROKER_PORT}/{REDIS_BROKER_DB_INDEX}",
|
||||
)
|
||||
|
||||
CELERY_BROKER_URL = REDIS_BROKER_URL.replace("unix:", "redis+socket:")
|
||||
CELERY_RESULT_BACKEND = REDIS_BROKER_URL.replace("unix:", "redis+socket:")
|
||||
CELERY_BROKER_URL = env(
|
||||
"CELERY_BROKER_URL", REDIS_BROKER_URL.replace("unix:", "redis+socket:")
|
||||
)
|
||||
CELERY_RESULT_BACKEND = env(
|
||||
"CELERY_RESULT_BACKEND", REDIS_BROKER_URL.replace("unix:", "redis+socket:")
|
||||
)
|
||||
|
||||
CELERY_DEFAULT_QUEUE = "low_priority"
|
||||
CELERY_CREATE_MISSING_QUEUES = True
|
||||
|
|
|
@ -15,11 +15,8 @@ env =
|
|||
ALLOWED_HOSTS = your.domain.here
|
||||
BOOKWYRM_DATABASE_BACKEND = postgres
|
||||
MEDIA_ROOT = images/
|
||||
CELERY_BROKER =
|
||||
REDIS_BROKER_PORT = 6379
|
||||
REDIS_BROKER_PASSWORD = beep
|
||||
REDIS_ACTIVITY_PORT = 6379
|
||||
REDIS_ACTIVITY_PASSWORD = beep
|
||||
CELERY_BROKER_URL = memory://
|
||||
CELERY_RESULT_BACKEND = cache+memory://
|
||||
USE_DUMMY_CACHE = true
|
||||
FLOWER_PORT = 8888
|
||||
EMAIL_HOST = smtp.mailgun.org
|
||||
|
|
|
@ -4,7 +4,7 @@ boto3==1.34.74
|
|||
bw-file-resubmit==0.6.0rc2
|
||||
celery==5.3.6
|
||||
colorthief==0.2.1
|
||||
Django==4.2.14
|
||||
Django==4.2.15
|
||||
django-celery-beat==2.6.0
|
||||
django-compressor==4.4
|
||||
django-csp==3.8
|
||||
|
@ -49,7 +49,7 @@ black==22.*
|
|||
celery-types==0.22.0
|
||||
django-stubs[compatible-mypy]==4.2.7
|
||||
mypy==1.7.1
|
||||
pylint==2.17.7
|
||||
pylint==3.2.6
|
||||
pytest==8.1.1
|
||||
pytest-cov==5.0.0
|
||||
pytest-django==4.8.0
|
||||
|
|
Loading…
Reference in a new issue