mirror of
https://github.com/bookwyrm-social/bookwyrm.git
synced 2024-06-02 06:40:31 +00:00
Merge pull request #2258 from bookwyrm-social/form-perms
Check permissions automatically on form save
This commit is contained in:
commit
fdc477afdf
|
@ -2,13 +2,14 @@
|
||||||
import datetime
|
import datetime
|
||||||
|
|
||||||
from django import forms
|
from django import forms
|
||||||
|
from django.core.exceptions import PermissionDenied
|
||||||
from django.forms import widgets
|
from django.forms import widgets
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
from django_celery_beat.models import IntervalSchedule
|
from django_celery_beat.models import IntervalSchedule
|
||||||
|
|
||||||
from bookwyrm import models
|
from bookwyrm import models
|
||||||
from .custom_form import CustomForm
|
from .custom_form import CustomForm, StyledForm
|
||||||
|
|
||||||
|
|
||||||
# pylint: disable=missing-class-docstring
|
# pylint: disable=missing-class-docstring
|
||||||
|
@ -130,7 +131,7 @@ class AutoModRuleForm(CustomForm):
|
||||||
fields = ["string_match", "flag_users", "flag_statuses", "created_by"]
|
fields = ["string_match", "flag_users", "flag_statuses", "created_by"]
|
||||||
|
|
||||||
|
|
||||||
class IntervalScheduleForm(CustomForm):
|
class IntervalScheduleForm(StyledForm):
|
||||||
class Meta:
|
class Meta:
|
||||||
model = IntervalSchedule
|
model = IntervalSchedule
|
||||||
fields = ["every", "period"]
|
fields = ["every", "period"]
|
||||||
|
@ -139,3 +140,10 @@ class IntervalScheduleForm(CustomForm):
|
||||||
"every": forms.NumberInput(attrs={"aria-describedby": "desc_every"}),
|
"every": forms.NumberInput(attrs={"aria-describedby": "desc_every"}),
|
||||||
"period": forms.Select(attrs={"aria-describedby": "desc_period"}),
|
"period": forms.Select(attrs={"aria-describedby": "desc_period"}),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# pylint: disable=arguments-differ
|
||||||
|
def save(self, request, *args, **kwargs):
|
||||||
|
"""This is an outside model so the perms check works differently"""
|
||||||
|
if not request.user.has_perm("bookwyrm.moderate_user"):
|
||||||
|
raise PermissionDenied()
|
||||||
|
return super().save(*args, **kwargs)
|
||||||
|
|
|
@ -4,7 +4,7 @@ from django.forms import ModelForm
|
||||||
from django.forms.widgets import Textarea
|
from django.forms.widgets import Textarea
|
||||||
|
|
||||||
|
|
||||||
class CustomForm(ModelForm):
|
class StyledForm(ModelForm):
|
||||||
"""add css classes to the forms"""
|
"""add css classes to the forms"""
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
|
@ -16,7 +16,7 @@ class CustomForm(ModelForm):
|
||||||
css_classes["checkbox"] = "checkbox"
|
css_classes["checkbox"] = "checkbox"
|
||||||
css_classes["textarea"] = "textarea"
|
css_classes["textarea"] = "textarea"
|
||||||
# pylint: disable=super-with-arguments
|
# pylint: disable=super-with-arguments
|
||||||
super(CustomForm, self).__init__(*args, **kwargs)
|
super().__init__(*args, **kwargs)
|
||||||
for visible in self.visible_fields():
|
for visible in self.visible_fields():
|
||||||
if hasattr(visible.field.widget, "input_type"):
|
if hasattr(visible.field.widget, "input_type"):
|
||||||
input_type = visible.field.widget.input_type
|
input_type = visible.field.widget.input_type
|
||||||
|
@ -24,3 +24,13 @@ class CustomForm(ModelForm):
|
||||||
input_type = "textarea"
|
input_type = "textarea"
|
||||||
visible.field.widget.attrs["rows"] = 5
|
visible.field.widget.attrs["rows"] = 5
|
||||||
visible.field.widget.attrs["class"] = css_classes[input_type]
|
visible.field.widget.attrs["class"] = css_classes[input_type]
|
||||||
|
|
||||||
|
|
||||||
|
class CustomForm(StyledForm):
|
||||||
|
"""Check permissions on save"""
|
||||||
|
|
||||||
|
# pylint: disable=arguments-differ
|
||||||
|
def save(self, request, *args, **kwargs):
|
||||||
|
"""Save and check perms"""
|
||||||
|
self.instance.raise_not_editable(request.user)
|
||||||
|
return super().save(*args, **kwargs)
|
||||||
|
|
65
bookwyrm/migrations/0158_auto_20220919_1634.py
Normal file
65
bookwyrm/migrations/0158_auto_20220919_1634.py
Normal file
|
@ -0,0 +1,65 @@
|
||||||
|
# Generated by Django 3.2.15 on 2022-09-19 16:34
|
||||||
|
|
||||||
|
import bookwyrm.models.fields
|
||||||
|
from django.db import migrations, models
|
||||||
|
import django.utils.timezone
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
("bookwyrm", "0157_auto_20220909_2338"),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name="automod",
|
||||||
|
name="created_date",
|
||||||
|
field=models.DateTimeField(
|
||||||
|
auto_now_add=True, default=django.utils.timezone.now
|
||||||
|
),
|
||||||
|
preserve_default=False,
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name="automod",
|
||||||
|
name="remote_id",
|
||||||
|
field=bookwyrm.models.fields.RemoteIdField(
|
||||||
|
max_length=255,
|
||||||
|
null=True,
|
||||||
|
validators=[bookwyrm.models.fields.validate_remote_id],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name="automod",
|
||||||
|
name="updated_date",
|
||||||
|
field=models.DateTimeField(auto_now=True),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name="emailblocklist",
|
||||||
|
name="remote_id",
|
||||||
|
field=bookwyrm.models.fields.RemoteIdField(
|
||||||
|
max_length=255,
|
||||||
|
null=True,
|
||||||
|
validators=[bookwyrm.models.fields.validate_remote_id],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name="emailblocklist",
|
||||||
|
name="updated_date",
|
||||||
|
field=models.DateTimeField(auto_now=True),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name="ipblocklist",
|
||||||
|
name="remote_id",
|
||||||
|
field=bookwyrm.models.fields.RemoteIdField(
|
||||||
|
max_length=255,
|
||||||
|
null=True,
|
||||||
|
validators=[bookwyrm.models.fields.validate_remote_id],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name="ipblocklist",
|
||||||
|
name="updated_date",
|
||||||
|
field=models.DateTimeField(auto_now=True),
|
||||||
|
),
|
||||||
|
]
|
|
@ -3,18 +3,33 @@ from functools import reduce
|
||||||
import operator
|
import operator
|
||||||
|
|
||||||
from django.apps import apps
|
from django.apps import apps
|
||||||
|
from django.core.exceptions import PermissionDenied
|
||||||
from django.db import models, transaction
|
from django.db import models, transaction
|
||||||
from django.db.models import Q
|
from django.db.models import Q
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
from bookwyrm.tasks import app
|
from bookwyrm.tasks import app
|
||||||
|
from .base_model import BookWyrmModel
|
||||||
from .user import User
|
from .user import User
|
||||||
|
|
||||||
|
|
||||||
class EmailBlocklist(models.Model):
|
class AdminModel(BookWyrmModel):
|
||||||
|
"""Overrides the permissions methods"""
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
"""this is just here to provide default fields for other models"""
|
||||||
|
|
||||||
|
abstract = True
|
||||||
|
|
||||||
|
def raise_not_editable(self, viewer):
|
||||||
|
if viewer.has_perm("bookwyrm.moderate_user"):
|
||||||
|
return
|
||||||
|
raise PermissionDenied()
|
||||||
|
|
||||||
|
|
||||||
|
class EmailBlocklist(AdminModel):
|
||||||
"""blocked email addresses"""
|
"""blocked email addresses"""
|
||||||
|
|
||||||
created_date = models.DateTimeField(auto_now_add=True)
|
|
||||||
domain = models.CharField(max_length=255, unique=True)
|
domain = models.CharField(max_length=255, unique=True)
|
||||||
is_active = models.BooleanField(default=True)
|
is_active = models.BooleanField(default=True)
|
||||||
|
|
||||||
|
@ -29,10 +44,9 @@ class EmailBlocklist(models.Model):
|
||||||
return User.objects.filter(email__endswith=f"@{self.domain}")
|
return User.objects.filter(email__endswith=f"@{self.domain}")
|
||||||
|
|
||||||
|
|
||||||
class IPBlocklist(models.Model):
|
class IPBlocklist(AdminModel):
|
||||||
"""blocked ip addresses"""
|
"""blocked ip addresses"""
|
||||||
|
|
||||||
created_date = models.DateTimeField(auto_now_add=True)
|
|
||||||
address = models.CharField(max_length=255, unique=True)
|
address = models.CharField(max_length=255, unique=True)
|
||||||
is_active = models.BooleanField(default=True)
|
is_active = models.BooleanField(default=True)
|
||||||
|
|
||||||
|
@ -42,7 +56,7 @@ class IPBlocklist(models.Model):
|
||||||
ordering = ("-created_date",)
|
ordering = ("-created_date",)
|
||||||
|
|
||||||
|
|
||||||
class AutoMod(models.Model):
|
class AutoMod(AdminModel):
|
||||||
"""rules to automatically flag suspicious activity"""
|
"""rules to automatically flag suspicious activity"""
|
||||||
|
|
||||||
string_match = models.CharField(max_length=200, unique=True)
|
string_match = models.CharField(max_length=200, unique=True)
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
""" flagged for moderation """
|
""" flagged for moderation """
|
||||||
|
from django.core.exceptions import PermissionDenied
|
||||||
from django.db import models
|
from django.db import models
|
||||||
|
|
||||||
from bookwyrm.settings import DOMAIN
|
from bookwyrm.settings import DOMAIN
|
||||||
from .base_model import BookWyrmModel
|
from .base_model import BookWyrmModel
|
||||||
|
|
||||||
|
@ -21,6 +23,12 @@ class Report(BookWyrmModel):
|
||||||
links = models.ManyToManyField("Link", blank=True)
|
links = models.ManyToManyField("Link", blank=True)
|
||||||
resolved = models.BooleanField(default=False)
|
resolved = models.BooleanField(default=False)
|
||||||
|
|
||||||
|
def raise_not_editable(self, viewer):
|
||||||
|
"""instead of user being the owner field, it's reporter"""
|
||||||
|
if self.reporter == viewer or viewer.has_perm("bookwyrm.moderate_user"):
|
||||||
|
return
|
||||||
|
raise PermissionDenied()
|
||||||
|
|
||||||
def get_remote_id(self):
|
def get_remote_id(self):
|
||||||
return f"https://{DOMAIN}/settings/reports/{self.id}"
|
return f"https://{DOMAIN}/settings/reports/{self.id}"
|
||||||
|
|
||||||
|
|
|
@ -3,6 +3,7 @@ import datetime
|
||||||
from urllib.parse import urljoin
|
from urllib.parse import urljoin
|
||||||
import uuid
|
import uuid
|
||||||
|
|
||||||
|
from django.core.exceptions import PermissionDenied
|
||||||
from django.db import models, IntegrityError
|
from django.db import models, IntegrityError
|
||||||
from django.dispatch import receiver
|
from django.dispatch import receiver
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
|
@ -15,7 +16,23 @@ from .user import User
|
||||||
from .fields import get_absolute_url
|
from .fields import get_absolute_url
|
||||||
|
|
||||||
|
|
||||||
class SiteSettings(models.Model):
|
class SiteModel(models.Model):
|
||||||
|
"""we just need edit perms"""
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
"""this is just here to provide default fields for other models"""
|
||||||
|
|
||||||
|
abstract = True
|
||||||
|
|
||||||
|
# pylint: disable=no-self-use
|
||||||
|
def raise_not_editable(self, viewer):
|
||||||
|
"""Check if the user has the right permissions"""
|
||||||
|
if viewer.has_perm("bookwyrm.edit_instance_settings"):
|
||||||
|
return
|
||||||
|
raise PermissionDenied()
|
||||||
|
|
||||||
|
|
||||||
|
class SiteSettings(SiteModel):
|
||||||
"""customized settings for this instance"""
|
"""customized settings for this instance"""
|
||||||
|
|
||||||
name = models.CharField(default="BookWyrm", max_length=100)
|
name = models.CharField(default="BookWyrm", max_length=100)
|
||||||
|
@ -115,7 +132,7 @@ class SiteSettings(models.Model):
|
||||||
super().save(*args, **kwargs)
|
super().save(*args, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
class Theme(models.Model):
|
class Theme(SiteModel):
|
||||||
"""Theme files"""
|
"""Theme files"""
|
||||||
|
|
||||||
created_date = models.DateTimeField(auto_now_add=True)
|
created_date = models.DateTimeField(auto_now_add=True)
|
||||||
|
@ -138,6 +155,13 @@ class SiteInvite(models.Model):
|
||||||
user = models.ForeignKey(User, on_delete=models.CASCADE)
|
user = models.ForeignKey(User, on_delete=models.CASCADE)
|
||||||
invitees = models.ManyToManyField(User, related_name="invitees")
|
invitees = models.ManyToManyField(User, related_name="invitees")
|
||||||
|
|
||||||
|
# pylint: disable=no-self-use
|
||||||
|
def raise_not_editable(self, viewer):
|
||||||
|
"""Admins only"""
|
||||||
|
if viewer.has_perm("bookwyrm.create_invites"):
|
||||||
|
return
|
||||||
|
raise PermissionDenied()
|
||||||
|
|
||||||
def valid(self):
|
def valid(self):
|
||||||
"""make sure it hasn't expired or been used"""
|
"""make sure it hasn't expired or been used"""
|
||||||
return (self.expiry is None or self.expiry > timezone.now()) and (
|
return (self.expiry is None or self.expiry > timezone.now()) and (
|
||||||
|
@ -161,6 +185,12 @@ class InviteRequest(BookWyrmModel):
|
||||||
invite_sent = models.BooleanField(default=False)
|
invite_sent = models.BooleanField(default=False)
|
||||||
ignored = models.BooleanField(default=False)
|
ignored = models.BooleanField(default=False)
|
||||||
|
|
||||||
|
def raise_not_editable(self, viewer):
|
||||||
|
"""Only check perms on edit, not create"""
|
||||||
|
if not self.id or viewer.has_perm("bookwyrm.create_invites"):
|
||||||
|
return
|
||||||
|
raise PermissionDenied()
|
||||||
|
|
||||||
def save(self, *args, **kwargs):
|
def save(self, *args, **kwargs):
|
||||||
"""don't create a request for a registered email"""
|
"""don't create a request for a registered email"""
|
||||||
if not self.id and User.objects.filter(email=self.email).exists():
|
if not self.id and User.objects.filter(email=self.email).exists():
|
||||||
|
|
|
@ -5,6 +5,7 @@ from urllib.parse import urlparse
|
||||||
from django.apps import apps
|
from django.apps import apps
|
||||||
from django.contrib.auth.models import AbstractUser, Group
|
from django.contrib.auth.models import AbstractUser, Group
|
||||||
from django.contrib.postgres.fields import ArrayField, CICharField
|
from django.contrib.postgres.fields import ArrayField, CICharField
|
||||||
|
from django.core.exceptions import PermissionDenied
|
||||||
from django.dispatch import receiver
|
from django.dispatch import receiver
|
||||||
from django.db import models, transaction
|
from django.db import models, transaction
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
|
@ -401,6 +402,12 @@ class User(OrderedCollectionPageMixin, AbstractUser):
|
||||||
editable=False,
|
editable=False,
|
||||||
).save(broadcast=False)
|
).save(broadcast=False)
|
||||||
|
|
||||||
|
def raise_not_editable(self, viewer):
|
||||||
|
"""Who can edit the user object?"""
|
||||||
|
if self == viewer or viewer.has_perm("bookwyrm.moderate_user"):
|
||||||
|
return
|
||||||
|
raise PermissionDenied()
|
||||||
|
|
||||||
|
|
||||||
class KeyPair(ActivitypubMixin, BookWyrmModel):
|
class KeyPair(ActivitypubMixin, BookWyrmModel):
|
||||||
"""public and private keys for a user"""
|
"""public and private keys for a user"""
|
||||||
|
|
|
@ -54,7 +54,6 @@
|
||||||
method="POST"
|
method="POST"
|
||||||
action="{% url 'settings-themes' %}"
|
action="{% url 'settings-themes' %}"
|
||||||
class="box"
|
class="box"
|
||||||
enctype="multipart/form-data"
|
|
||||||
>
|
>
|
||||||
<fieldset>
|
<fieldset>
|
||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
|
|
|
@ -15,6 +15,7 @@ from bookwyrm.tests.validate_html import validate_html
|
||||||
class AutomodViews(TestCase):
|
class AutomodViews(TestCase):
|
||||||
"""every response to a get request, html or json"""
|
"""every response to a get request, html or json"""
|
||||||
|
|
||||||
|
# pylint: disable=invalid-name
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
"""we need basic test data and mocks"""
|
"""we need basic test data and mocks"""
|
||||||
self.factory = RequestFactory()
|
self.factory = RequestFactory()
|
||||||
|
|
|
@ -17,6 +17,7 @@ from bookwyrm.tests.validate_html import validate_html
|
||||||
class FederationViews(TestCase):
|
class FederationViews(TestCase):
|
||||||
"""every response to a get request, html or json"""
|
"""every response to a get request, html or json"""
|
||||||
|
|
||||||
|
# pylint: disable=invalid-name
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
"""we need basic test data and mocks"""
|
"""we need basic test data and mocks"""
|
||||||
self.factory = RequestFactory()
|
self.factory = RequestFactory()
|
||||||
|
|
88
bookwyrm/tests/views/admin/test_themes.py
Normal file
88
bookwyrm/tests/views/admin/test_themes.py
Normal file
|
@ -0,0 +1,88 @@
|
||||||
|
""" test for app action functionality """
|
||||||
|
from unittest.mock import patch
|
||||||
|
|
||||||
|
from django.contrib.auth.models import Group
|
||||||
|
from django.core.exceptions import PermissionDenied
|
||||||
|
from django.template.response import TemplateResponse
|
||||||
|
from django.test import TestCase
|
||||||
|
from django.test.client import RequestFactory
|
||||||
|
|
||||||
|
from bookwyrm import forms, models, views
|
||||||
|
from bookwyrm.management.commands import initdb
|
||||||
|
from bookwyrm.tests.validate_html import validate_html
|
||||||
|
|
||||||
|
|
||||||
|
class AdminThemesViews(TestCase):
|
||||||
|
"""Edit site settings"""
|
||||||
|
|
||||||
|
# pylint: disable=invalid-name
|
||||||
|
def setUp(self):
|
||||||
|
"""we need basic test data and mocks"""
|
||||||
|
self.factory = RequestFactory()
|
||||||
|
with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch(
|
||||||
|
"bookwyrm.activitystreams.populate_stream_task.delay"
|
||||||
|
), patch("bookwyrm.lists_stream.populate_lists_task.delay"):
|
||||||
|
self.local_user = models.User.objects.create_user(
|
||||||
|
"mouse@local.com",
|
||||||
|
"mouse@mouse.mouse",
|
||||||
|
"password",
|
||||||
|
local=True,
|
||||||
|
localname="mouse",
|
||||||
|
)
|
||||||
|
self.another_user = models.User.objects.create_user(
|
||||||
|
"rat@local.com",
|
||||||
|
"rat@rat.rat",
|
||||||
|
"password",
|
||||||
|
local=True,
|
||||||
|
localname="rat",
|
||||||
|
)
|
||||||
|
initdb.init_groups()
|
||||||
|
initdb.init_permissions()
|
||||||
|
group = Group.objects.get(name="admin")
|
||||||
|
self.local_user.groups.set([group])
|
||||||
|
|
||||||
|
self.site = models.SiteSettings.objects.create()
|
||||||
|
|
||||||
|
def test_themes_get(self):
|
||||||
|
"""there are so many views, this just makes sure it LOADS"""
|
||||||
|
view = views.Themes.as_view()
|
||||||
|
request = self.factory.get("")
|
||||||
|
request.user = self.local_user
|
||||||
|
|
||||||
|
result = view(request)
|
||||||
|
self.assertIsInstance(result, TemplateResponse)
|
||||||
|
validate_html(result.render())
|
||||||
|
self.assertEqual(result.status_code, 200)
|
||||||
|
|
||||||
|
def test_themes_post(self):
|
||||||
|
"""there are so many views, this just makes sure it LOADS"""
|
||||||
|
view = views.Themes.as_view()
|
||||||
|
|
||||||
|
form = forms.ThemeForm()
|
||||||
|
form.data["name"] = "test theme"
|
||||||
|
form.data["path"] = "not/a/path.scss"
|
||||||
|
request = self.factory.post("", form.data)
|
||||||
|
request.user = self.local_user
|
||||||
|
|
||||||
|
result = view(request)
|
||||||
|
|
||||||
|
self.assertIsInstance(result, TemplateResponse)
|
||||||
|
validate_html(result.render())
|
||||||
|
self.assertEqual(result.status_code, 200)
|
||||||
|
|
||||||
|
theme = models.Theme.objects.last()
|
||||||
|
self.assertEqual(theme.name, "test theme")
|
||||||
|
self.assertEqual(theme.path, "not/a/path.scss")
|
||||||
|
|
||||||
|
def test_themes_post_forbidden(self):
|
||||||
|
"""there are so many views, this just makes sure it LOADS"""
|
||||||
|
view = views.Themes.as_view()
|
||||||
|
|
||||||
|
form = forms.ThemeForm()
|
||||||
|
form.data["name"] = "test theme"
|
||||||
|
form.data["path"] = "not/a/path.scss"
|
||||||
|
request = self.factory.post("", form.data)
|
||||||
|
request.user = self.another_user
|
||||||
|
|
||||||
|
with self.assertRaises(PermissionDenied):
|
||||||
|
view(request)
|
|
@ -14,6 +14,7 @@ from bookwyrm.tests.validate_html import validate_html
|
||||||
class InviteViews(TestCase):
|
class InviteViews(TestCase):
|
||||||
"""every response to a get request, html or json"""
|
"""every response to a get request, html or json"""
|
||||||
|
|
||||||
|
# pylint: disable=invalid-name
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
"""we need basic test data and mocks"""
|
"""we need basic test data and mocks"""
|
||||||
self.factory = RequestFactory()
|
self.factory = RequestFactory()
|
||||||
|
@ -82,6 +83,7 @@ class InviteViews(TestCase):
|
||||||
|
|
||||||
view = views.InviteRequest.as_view()
|
view = views.InviteRequest.as_view()
|
||||||
request = self.factory.post("", form.data)
|
request = self.factory.post("", form.data)
|
||||||
|
request.user = self.local_user
|
||||||
|
|
||||||
result = view(request)
|
result = view(request)
|
||||||
validate_html(result.render())
|
validate_html(result.render())
|
||||||
|
@ -96,6 +98,7 @@ class InviteViews(TestCase):
|
||||||
|
|
||||||
view = views.InviteRequest.as_view()
|
view = views.InviteRequest.as_view()
|
||||||
request = self.factory.post("", form.data)
|
request = self.factory.post("", form.data)
|
||||||
|
request.user = self.local_user
|
||||||
|
|
||||||
result = view(request)
|
result = view(request)
|
||||||
validate_html(result.render())
|
validate_html(result.render())
|
||||||
|
@ -109,6 +112,7 @@ class InviteViews(TestCase):
|
||||||
request = self.factory.get("")
|
request = self.factory.get("")
|
||||||
request.user = self.local_user
|
request.user = self.local_user
|
||||||
request.user.is_superuser = True
|
request.user.is_superuser = True
|
||||||
|
|
||||||
result = view(request)
|
result = view(request)
|
||||||
self.assertIsInstance(result, TemplateResponse)
|
self.assertIsInstance(result, TemplateResponse)
|
||||||
validate_html(result.render())
|
validate_html(result.render())
|
||||||
|
|
|
@ -15,6 +15,7 @@ from bookwyrm.tests.validate_html import validate_html
|
||||||
class ListViews(TestCase):
|
class ListViews(TestCase):
|
||||||
"""lists of lists"""
|
"""lists of lists"""
|
||||||
|
|
||||||
|
# pylint: disable=invalid-name
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
"""we need basic test data and mocks"""
|
"""we need basic test data and mocks"""
|
||||||
self.factory = RequestFactory()
|
self.factory = RequestFactory()
|
||||||
|
|
|
@ -11,6 +11,7 @@ from bookwyrm.tests.validate_html import validate_html
|
||||||
class ReportViews(TestCase):
|
class ReportViews(TestCase):
|
||||||
"""every response to a get request, html or json"""
|
"""every response to a get request, html or json"""
|
||||||
|
|
||||||
|
# pylint: disable=invalid-name
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
"""we need basic test data and mocks"""
|
"""we need basic test data and mocks"""
|
||||||
self.factory = RequestFactory()
|
self.factory = RequestFactory()
|
||||||
|
|
|
@ -102,7 +102,7 @@ class EditAnnouncement(View):
|
||||||
return TemplateResponse(
|
return TemplateResponse(
|
||||||
request, "settings/announcements/edit_announcement.html", data
|
request, "settings/announcements/edit_announcement.html", data
|
||||||
)
|
)
|
||||||
announcement = form.save()
|
announcement = form.save(request)
|
||||||
return redirect("settings-announcements", announcement.id)
|
return redirect("settings-announcements", announcement.id)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -34,7 +34,7 @@ class AutoMod(View):
|
||||||
"""add rule"""
|
"""add rule"""
|
||||||
form = forms.AutoModRuleForm(request.POST)
|
form = forms.AutoModRuleForm(request.POST)
|
||||||
if form.is_valid():
|
if form.is_valid():
|
||||||
form.save()
|
form.save(request)
|
||||||
form = forms.AutoModRuleForm()
|
form = forms.AutoModRuleForm()
|
||||||
|
|
||||||
data = automod_view_data()
|
data = automod_view_data()
|
||||||
|
@ -54,7 +54,7 @@ def schedule_automod_task(request):
|
||||||
return TemplateResponse(request, "settings/automod/rules.html", data)
|
return TemplateResponse(request, "settings/automod/rules.html", data)
|
||||||
|
|
||||||
with transaction.atomic():
|
with transaction.atomic():
|
||||||
schedule = form.save()
|
schedule = form.save(request)
|
||||||
PeriodicTask.objects.get_or_create(
|
PeriodicTask.objects.get_or_create(
|
||||||
interval=schedule,
|
interval=schedule,
|
||||||
name="automod-task",
|
name="automod-task",
|
||||||
|
|
|
@ -40,7 +40,7 @@ class EmailBlocklist(View):
|
||||||
return TemplateResponse(
|
return TemplateResponse(
|
||||||
request, "settings/email_blocklist/email_blocklist.html", data
|
request, "settings/email_blocklist/email_blocklist.html", data
|
||||||
)
|
)
|
||||||
form.save()
|
form.save(request)
|
||||||
|
|
||||||
data["form"] = forms.EmailBlocklistForm()
|
data["form"] = forms.EmailBlocklistForm()
|
||||||
return TemplateResponse(
|
return TemplateResponse(
|
||||||
|
|
|
@ -86,7 +86,7 @@ class AddFederatedServer(View):
|
||||||
return TemplateResponse(
|
return TemplateResponse(
|
||||||
request, "settings/federation/edit_instance.html", data
|
request, "settings/federation/edit_instance.html", data
|
||||||
)
|
)
|
||||||
server = form.save()
|
server = form.save(request)
|
||||||
return redirect("settings-federated-server", server.id)
|
return redirect("settings-federated-server", server.id)
|
||||||
|
|
||||||
|
|
||||||
|
@ -156,7 +156,7 @@ class FederatedServer(View):
|
||||||
"""update note"""
|
"""update note"""
|
||||||
server = get_object_or_404(models.FederatedServer, id=server)
|
server = get_object_or_404(models.FederatedServer, id=server)
|
||||||
server.notes = request.POST.get("notes")
|
server.notes = request.POST.get("notes")
|
||||||
server.save()
|
server.save(request)
|
||||||
return redirect("settings-federated-server", server.id)
|
return redirect("settings-federated-server", server.id)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -52,9 +52,9 @@ class ManageInvites(View):
|
||||||
if not form.is_valid():
|
if not form.is_valid():
|
||||||
return HttpResponseBadRequest(f"ERRORS: {form.errors}")
|
return HttpResponseBadRequest(f"ERRORS: {form.errors}")
|
||||||
|
|
||||||
invite = form.save(commit=False)
|
invite = form.save(request, commit=False)
|
||||||
invite.user = request.user
|
invite.user = request.user
|
||||||
invite.save()
|
invite.save(request)
|
||||||
|
|
||||||
paginated = Paginator(
|
paginated = Paginator(
|
||||||
models.SiteInvite.objects.filter(user=request.user).order_by(
|
models.SiteInvite.objects.filter(user=request.user).order_by(
|
||||||
|
@ -170,7 +170,7 @@ class InviteRequest(View):
|
||||||
received = False
|
received = False
|
||||||
if form.is_valid():
|
if form.is_valid():
|
||||||
received = True
|
received = True
|
||||||
form.save()
|
form.save(request)
|
||||||
|
|
||||||
data = {"request_form": form, "request_received": received}
|
data = {"request_form": form, "request_received": received}
|
||||||
return TemplateResponse(request, "landing/landing.html", data)
|
return TemplateResponse(request, "landing/landing.html", data)
|
||||||
|
|
|
@ -40,7 +40,7 @@ class IPBlocklist(View):
|
||||||
return TemplateResponse(
|
return TemplateResponse(
|
||||||
request, "settings/ip_blocklist/ip_blocklist.html", data
|
request, "settings/ip_blocklist/ip_blocklist.html", data
|
||||||
)
|
)
|
||||||
form.save()
|
form.save(request)
|
||||||
|
|
||||||
data["form"] = forms.IPBlocklistForm()
|
data["form"] = forms.IPBlocklistForm()
|
||||||
return TemplateResponse(
|
return TemplateResponse(
|
||||||
|
|
|
@ -39,7 +39,7 @@ class LinkDomain(View):
|
||||||
"""Set display name"""
|
"""Set display name"""
|
||||||
domain = get_object_or_404(models.LinkDomain, id=domain_id)
|
domain = get_object_or_404(models.LinkDomain, id=domain_id)
|
||||||
form = forms.LinkDomainForm(request.POST, instance=domain)
|
form = forms.LinkDomainForm(request.POST, instance=domain)
|
||||||
form.save()
|
form.save(request)
|
||||||
return redirect("settings-link-domain", status=status)
|
return redirect("settings-link-domain", status=status)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -29,7 +29,7 @@ class Site(View):
|
||||||
if not form.is_valid():
|
if not form.is_valid():
|
||||||
data = {"site_form": form}
|
data = {"site_form": form}
|
||||||
return TemplateResponse(request, "settings/site.html", data)
|
return TemplateResponse(request, "settings/site.html", data)
|
||||||
site = form.save()
|
site = form.save(request)
|
||||||
|
|
||||||
data = {"site_form": forms.SiteForm(instance=site), "success": True}
|
data = {"site_form": forms.SiteForm(instance=site), "success": True}
|
||||||
return TemplateResponse(request, "settings/site.html", data)
|
return TemplateResponse(request, "settings/site.html", data)
|
||||||
|
|
|
@ -24,9 +24,9 @@ class Themes(View):
|
||||||
|
|
||||||
def post(self, request):
|
def post(self, request):
|
||||||
"""edit the site settings"""
|
"""edit the site settings"""
|
||||||
form = forms.ThemeForm(request.POST, request.FILES)
|
form = forms.ThemeForm(request.POST)
|
||||||
if form.is_valid():
|
if form.is_valid():
|
||||||
form.save()
|
form.save(request)
|
||||||
|
|
||||||
data = get_view_data()
|
data = get_view_data()
|
||||||
|
|
||||||
|
|
|
@ -88,6 +88,6 @@ class UserAdmin(View):
|
||||||
else:
|
else:
|
||||||
form = forms.UserGroupForm(request.POST, instance=user)
|
form = forms.UserGroupForm(request.POST, instance=user)
|
||||||
if form.is_valid():
|
if form.is_valid():
|
||||||
form.save()
|
form.save(request)
|
||||||
data = {"user": user, "group_form": form}
|
data = {"user": user, "group_form": form}
|
||||||
return TemplateResponse(request, "settings/users/user.html", data)
|
return TemplateResponse(request, "settings/users/user.html", data)
|
||||||
|
|
|
@ -68,7 +68,7 @@ class EditAuthor(View):
|
||||||
if not form.is_valid():
|
if not form.is_valid():
|
||||||
data = {"author": author, "form": form}
|
data = {"author": author, "form": form}
|
||||||
return TemplateResponse(request, "author/edit_author.html", data)
|
return TemplateResponse(request, "author/edit_author.html", data)
|
||||||
author = form.save()
|
author = form.save(request)
|
||||||
|
|
||||||
return redirect(f"/author/{author.id}")
|
return redirect(f"/author/{author.id}")
|
||||||
|
|
||||||
|
|
|
@ -56,7 +56,7 @@ class EditBook(View):
|
||||||
for author_id in remove_authors:
|
for author_id in remove_authors:
|
||||||
book.authors.remove(author_id)
|
book.authors.remove(author_id)
|
||||||
|
|
||||||
book = form.save(commit=False)
|
book = form.save(request, commit=False)
|
||||||
|
|
||||||
url = request.POST.get("cover-url")
|
url = request.POST.get("cover-url")
|
||||||
if url:
|
if url:
|
||||||
|
@ -119,7 +119,7 @@ class CreateBook(View):
|
||||||
return TemplateResponse(request, "book/edit/edit_book.html", data)
|
return TemplateResponse(request, "book/edit/edit_book.html", data)
|
||||||
|
|
||||||
with transaction.atomic():
|
with transaction.atomic():
|
||||||
book = form.save()
|
book = form.save(request)
|
||||||
parent_work = get_object_or_404(models.Work, id=parent_work_id)
|
parent_work = get_object_or_404(models.Work, id=parent_work_id)
|
||||||
book.parent_work = parent_work
|
book.parent_work = parent_work
|
||||||
|
|
||||||
|
@ -229,7 +229,7 @@ class ConfirmEditBook(View):
|
||||||
|
|
||||||
with transaction.atomic():
|
with transaction.atomic():
|
||||||
# save book
|
# save book
|
||||||
book = form.save()
|
book = form.save(request)
|
||||||
|
|
||||||
# add known authors
|
# add known authors
|
||||||
authors = None
|
authors = None
|
||||||
|
|
|
@ -34,7 +34,7 @@ class BookFileLinks(View):
|
||||||
"""Edit a link"""
|
"""Edit a link"""
|
||||||
link = get_object_or_404(models.FileLink, id=link_id, book=book_id)
|
link = get_object_or_404(models.FileLink, id=link_id, book=book_id)
|
||||||
form = forms.FileLinkForm(request.POST, instance=link)
|
form = forms.FileLinkForm(request.POST, instance=link)
|
||||||
form.save()
|
form.save(request)
|
||||||
return self.get(request, book_id)
|
return self.get(request, book_id)
|
||||||
|
|
||||||
|
|
||||||
|
@ -76,7 +76,7 @@ class AddFileLink(View):
|
||||||
request, "book/file_links/file_link_page.html", data
|
request, "book/file_links/file_link_page.html", data
|
||||||
)
|
)
|
||||||
|
|
||||||
link = form.save()
|
link = form.save(request)
|
||||||
book.file_links.add(link)
|
book.file_links.add(link)
|
||||||
book.last_edited_by = request.user
|
book.last_edited_by = request.user
|
||||||
book.save()
|
book.save()
|
||||||
|
|
|
@ -30,7 +30,7 @@ class Feed(View):
|
||||||
form = forms.FeedStatusTypesForm(request.POST, instance=request.user)
|
form = forms.FeedStatusTypesForm(request.POST, instance=request.user)
|
||||||
if form.is_valid():
|
if form.is_valid():
|
||||||
# workaround to avoid broadcasting this change
|
# workaround to avoid broadcasting this change
|
||||||
user = form.save(commit=False)
|
user = form.save(request, commit=False)
|
||||||
user.save(broadcast=False, update_fields=["feed_status_types"])
|
user.save(broadcast=False, update_fields=["feed_status_types"])
|
||||||
filters_applied = True
|
filters_applied = True
|
||||||
|
|
||||||
|
|
|
@ -38,7 +38,7 @@ class GetStartedProfile(View):
|
||||||
if not form.is_valid():
|
if not form.is_valid():
|
||||||
data = {"form": form, "next": "get-started-books"}
|
data = {"form": form, "next": "get-started-books"}
|
||||||
return TemplateResponse(request, "get_started/profile.html", data)
|
return TemplateResponse(request, "get_started/profile.html", data)
|
||||||
save_user_form(form)
|
save_user_form(request, form)
|
||||||
return redirect(self.next_view)
|
return redirect(self.next_view)
|
||||||
|
|
||||||
|
|
||||||
|
@ -82,7 +82,6 @@ class GetStartedBooks(View):
|
||||||
for (book_id, shelf_id) in shelve_actions:
|
for (book_id, shelf_id) in shelve_actions:
|
||||||
book = get_object_or_404(models.Edition, id=book_id)
|
book = get_object_or_404(models.Edition, id=book_id)
|
||||||
shelf = get_object_or_404(models.Shelf, id=shelf_id)
|
shelf = get_object_or_404(models.Shelf, id=shelf_id)
|
||||||
shelf.raise_not_editable(request.user)
|
|
||||||
|
|
||||||
models.ShelfBook.objects.create(book=book, shelf=shelf, user=request.user)
|
models.ShelfBook.objects.create(book=book, shelf=shelf, user=request.user)
|
||||||
return redirect(self.next_view)
|
return redirect(self.next_view)
|
||||||
|
|
|
@ -48,8 +48,6 @@ class Goal(View):
|
||||||
year = int(year)
|
year = int(year)
|
||||||
user = get_user_from_username(request.user, username)
|
user = get_user_from_username(request.user, username)
|
||||||
goal = models.AnnualGoal.objects.filter(year=year, user=user).first()
|
goal = models.AnnualGoal.objects.filter(year=year, user=user).first()
|
||||||
if goal:
|
|
||||||
goal.raise_not_editable(request.user)
|
|
||||||
|
|
||||||
form = forms.GoalForm(request.POST, instance=goal)
|
form = forms.GoalForm(request.POST, instance=goal)
|
||||||
if not form.is_valid():
|
if not form.is_valid():
|
||||||
|
@ -59,7 +57,7 @@ class Goal(View):
|
||||||
"year": year,
|
"year": year,
|
||||||
}
|
}
|
||||||
return TemplateResponse(request, "user/goal.html", data)
|
return TemplateResponse(request, "user/goal.html", data)
|
||||||
goal = form.save()
|
goal = form.save(request)
|
||||||
|
|
||||||
if request.POST.get("post-status"):
|
if request.POST.get("post-status"):
|
||||||
# create status, if appropriate
|
# create status, if appropriate
|
||||||
|
|
|
@ -52,7 +52,7 @@ class Group(View):
|
||||||
form = forms.GroupForm(request.POST, instance=user_group)
|
form = forms.GroupForm(request.POST, instance=user_group)
|
||||||
if not form.is_valid():
|
if not form.is_valid():
|
||||||
return redirect("group", user_group.id)
|
return redirect("group", user_group.id)
|
||||||
user_group = form.save()
|
user_group = form.save(request)
|
||||||
|
|
||||||
# let the other members know something about the group changed
|
# let the other members know something about the group changed
|
||||||
memberships = models.GroupMember.objects.filter(group=user_group)
|
memberships = models.GroupMember.objects.filter(group=user_group)
|
||||||
|
@ -113,10 +113,8 @@ class UserGroups(View):
|
||||||
if not form.is_valid():
|
if not form.is_valid():
|
||||||
return redirect(request.user.local_path + "/groups")
|
return redirect(request.user.local_path + "/groups")
|
||||||
|
|
||||||
group = form.save(commit=False)
|
|
||||||
group.raise_not_editable(request.user)
|
|
||||||
with transaction.atomic():
|
with transaction.atomic():
|
||||||
group.save()
|
group = form.save(request)
|
||||||
# add the creator as a group member
|
# add the creator as a group member
|
||||||
models.GroupMember.objects.create(group=group, user=request.user)
|
models.GroupMember.objects.create(group=group, user=request.user)
|
||||||
return redirect("group", group.id)
|
return redirect("group", group.id)
|
||||||
|
@ -129,10 +127,13 @@ class FindUsers(View):
|
||||||
# this is mostly borrowed from the Get Started friend finder
|
# this is mostly borrowed from the Get Started friend finder
|
||||||
|
|
||||||
def get(self, request, group_id):
|
def get(self, request, group_id):
|
||||||
"""basic profile info"""
|
"""Search for a user to add the a group, or load suggested users cache"""
|
||||||
user_query = request.GET.get("user_query")
|
user_query = request.GET.get("user_query")
|
||||||
group = get_object_or_404(models.Group, id=group_id)
|
group = get_object_or_404(models.Group, id=group_id)
|
||||||
|
|
||||||
|
# only users who can edit can add users
|
||||||
group.raise_not_editable(request.user)
|
group.raise_not_editable(request.user)
|
||||||
|
|
||||||
lists = (
|
lists = (
|
||||||
models.List.privacy_filter(request.user)
|
models.List.privacy_filter(request.user)
|
||||||
.filter(group=group)
|
.filter(group=group)
|
||||||
|
|
|
@ -31,7 +31,6 @@ class Curate(View):
|
||||||
def post(self, request, list_id):
|
def post(self, request, list_id):
|
||||||
"""edit a book_list"""
|
"""edit a book_list"""
|
||||||
book_list = get_object_or_404(models.List, id=list_id)
|
book_list = get_object_or_404(models.List, id=list_id)
|
||||||
book_list.raise_not_editable(request.user)
|
|
||||||
|
|
||||||
suggestion = get_object_or_404(models.ListItem, id=request.POST.get("item"))
|
suggestion = get_object_or_404(models.ListItem, id=request.POST.get("item"))
|
||||||
approved = request.POST.get("approved") == "true"
|
approved = request.POST.get("approved") == "true"
|
||||||
|
|
|
@ -81,13 +81,12 @@ class List(View):
|
||||||
def post(self, request, list_id):
|
def post(self, request, list_id):
|
||||||
"""edit a list"""
|
"""edit a list"""
|
||||||
book_list = get_object_or_404(models.List, id=list_id)
|
book_list = get_object_or_404(models.List, id=list_id)
|
||||||
book_list.raise_not_editable(request.user)
|
|
||||||
|
|
||||||
form = forms.ListForm(request.POST, instance=book_list)
|
form = forms.ListForm(request.POST, instance=book_list)
|
||||||
if not form.is_valid():
|
if not form.is_valid():
|
||||||
# this shouldn't happen
|
# this shouldn't happen
|
||||||
raise Exception(form.errors)
|
raise Exception(form.errors)
|
||||||
book_list = form.save()
|
book_list = form.save(request)
|
||||||
if not book_list.curation == "group":
|
if not book_list.curation == "group":
|
||||||
book_list.group = None
|
book_list.group = None
|
||||||
book_list.save(broadcast=False)
|
book_list.save(broadcast=False)
|
||||||
|
@ -196,7 +195,7 @@ def add_book(request):
|
||||||
if not form.is_valid():
|
if not form.is_valid():
|
||||||
return List().get(request, book_list.id, add_failed=True)
|
return List().get(request, book_list.id, add_failed=True)
|
||||||
|
|
||||||
item = form.save(commit=False)
|
item = form.save(request, commit=False)
|
||||||
|
|
||||||
if book_list.curation == "curated":
|
if book_list.curation == "curated":
|
||||||
# make a pending entry at the end of the list
|
# make a pending entry at the end of the list
|
||||||
|
@ -242,7 +241,6 @@ def set_book_position(request, list_item_id):
|
||||||
special care with the unique ordering per list.
|
special care with the unique ordering per list.
|
||||||
"""
|
"""
|
||||||
list_item = get_object_or_404(models.ListItem, id=list_item_id)
|
list_item = get_object_or_404(models.ListItem, id=list_item_id)
|
||||||
list_item.book_list.raise_not_editable(request.user)
|
|
||||||
try:
|
try:
|
||||||
int_position = int(request.POST.get("position"))
|
int_position = int(request.POST.get("position"))
|
||||||
except ValueError:
|
except ValueError:
|
||||||
|
|
|
@ -16,10 +16,9 @@ class ListItem(View):
|
||||||
def post(self, request, list_id, list_item):
|
def post(self, request, list_id, list_item):
|
||||||
"""Edit a list item's notes"""
|
"""Edit a list item's notes"""
|
||||||
list_item = get_object_or_404(models.ListItem, id=list_item, book_list=list_id)
|
list_item = get_object_or_404(models.ListItem, id=list_item, book_list=list_id)
|
||||||
list_item.raise_not_editable(request.user)
|
|
||||||
form = forms.ListItemForm(request.POST, instance=list_item)
|
form = forms.ListItemForm(request.POST, instance=list_item)
|
||||||
if form.is_valid():
|
if form.is_valid():
|
||||||
item = form.save(commit=False)
|
item = form.save(request, commit=False)
|
||||||
item.notes = to_markdown(item.notes)
|
item.notes = to_markdown(item.notes)
|
||||||
item.save()
|
item.save()
|
||||||
else:
|
else:
|
||||||
|
|
|
@ -36,8 +36,7 @@ class Lists(View):
|
||||||
form = forms.ListForm(request.POST)
|
form = forms.ListForm(request.POST)
|
||||||
if not form.is_valid():
|
if not form.is_valid():
|
||||||
return redirect("lists")
|
return redirect("lists")
|
||||||
book_list = form.save(commit=False)
|
book_list = form.save(request, commit=False)
|
||||||
book_list.raise_not_editable(request.user)
|
|
||||||
|
|
||||||
# list should not have a group if it is not group curated
|
# list should not have a group if it is not group curated
|
||||||
if not book_list.curation == "group":
|
if not book_list.curation == "group":
|
||||||
|
|
|
@ -34,14 +34,14 @@ class EditUser(View):
|
||||||
data = {"form": form, "user": request.user}
|
data = {"form": form, "user": request.user}
|
||||||
return TemplateResponse(request, "preferences/edit_user.html", data)
|
return TemplateResponse(request, "preferences/edit_user.html", data)
|
||||||
|
|
||||||
user = save_user_form(form)
|
user = save_user_form(request, form)
|
||||||
|
|
||||||
return set_language(user, redirect("user-feed", request.user.localname))
|
return set_language(user, redirect("user-feed", request.user.localname))
|
||||||
|
|
||||||
|
|
||||||
def save_user_form(form):
|
def save_user_form(request, form):
|
||||||
"""special handling for the user form"""
|
"""special handling for the user form"""
|
||||||
user = form.save(commit=False)
|
user = form.save(request, commit=False)
|
||||||
|
|
||||||
if "avatar" in form.files:
|
if "avatar" in form.files:
|
||||||
# crop and resize avatar upload
|
# crop and resize avatar upload
|
||||||
|
|
|
@ -159,7 +159,7 @@ class ReadThrough(View):
|
||||||
models.ReadThrough, id=request.POST.get("id")
|
models.ReadThrough, id=request.POST.get("id")
|
||||||
)
|
)
|
||||||
return TemplateResponse(request, "readthrough/readthrough.html", data)
|
return TemplateResponse(request, "readthrough/readthrough.html", data)
|
||||||
form.save()
|
form.save(request)
|
||||||
return redirect("book", book_id)
|
return redirect("book", book_id)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -33,7 +33,7 @@ class Report(View):
|
||||||
if not form.is_valid():
|
if not form.is_valid():
|
||||||
raise ValueError(form.errors)
|
raise ValueError(form.errors)
|
||||||
|
|
||||||
report = form.save()
|
report = form.save(request)
|
||||||
if report.links.exists():
|
if report.links.exists():
|
||||||
# revert the domain to pending
|
# revert the domain to pending
|
||||||
domain = report.links.first().domain
|
domain = report.links.first().domain
|
||||||
|
|
|
@ -113,7 +113,6 @@ class Shelf(View):
|
||||||
"""edit a shelf"""
|
"""edit a shelf"""
|
||||||
user = get_user_from_username(request.user, username)
|
user = get_user_from_username(request.user, username)
|
||||||
shelf = get_object_or_404(user.shelf_set, identifier=shelf_identifier)
|
shelf = get_object_or_404(user.shelf_set, identifier=shelf_identifier)
|
||||||
shelf.raise_not_editable(request.user)
|
|
||||||
|
|
||||||
# you can't change the name of the default shelves
|
# you can't change the name of the default shelves
|
||||||
if not shelf.editable and request.POST.get("name") != shelf.name:
|
if not shelf.editable and request.POST.get("name") != shelf.name:
|
||||||
|
@ -122,7 +121,7 @@ class Shelf(View):
|
||||||
form = forms.ShelfForm(request.POST, instance=shelf)
|
form = forms.ShelfForm(request.POST, instance=shelf)
|
||||||
if not form.is_valid():
|
if not form.is_valid():
|
||||||
return redirect(shelf.local_path)
|
return redirect(shelf.local_path)
|
||||||
shelf = form.save()
|
shelf = form.save(request)
|
||||||
return redirect(shelf.local_path)
|
return redirect(shelf.local_path)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -15,9 +15,7 @@ def create_shelf(request):
|
||||||
if not form.is_valid():
|
if not form.is_valid():
|
||||||
return redirect("user-shelves", request.user.localname)
|
return redirect("user-shelves", request.user.localname)
|
||||||
|
|
||||||
shelf = form.save(commit=False)
|
shelf = form.save(request)
|
||||||
shelf.raise_not_editable(request.user)
|
|
||||||
shelf.save()
|
|
||||||
return redirect(shelf.local_path)
|
return redirect(shelf.local_path)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -34,7 +34,6 @@ class EditStatus(View):
|
||||||
status = get_object_or_404(
|
status = get_object_or_404(
|
||||||
models.Status.objects.select_subclasses(), id=status_id
|
models.Status.objects.select_subclasses(), id=status_id
|
||||||
)
|
)
|
||||||
status.raise_not_editable(request.user)
|
|
||||||
|
|
||||||
status_type = "reply" if status.reply_parent else status.status_type.lower()
|
status_type = "reply" if status.reply_parent else status.status_type.lower()
|
||||||
data = {
|
data = {
|
||||||
|
@ -65,7 +64,6 @@ class CreateStatus(View):
|
||||||
existing_status = get_object_or_404(
|
existing_status = get_object_or_404(
|
||||||
models.Status.objects.select_subclasses(), id=existing_status_id
|
models.Status.objects.select_subclasses(), id=existing_status_id
|
||||||
)
|
)
|
||||||
existing_status.raise_not_editable(request.user)
|
|
||||||
existing_status.edited_date = timezone.now()
|
existing_status.edited_date = timezone.now()
|
||||||
|
|
||||||
status_type = status_type[0].upper() + status_type[1:]
|
status_type = status_type[0].upper() + status_type[1:]
|
||||||
|
@ -84,8 +82,7 @@ class CreateStatus(View):
|
||||||
return HttpResponseBadRequest()
|
return HttpResponseBadRequest()
|
||||||
return redirect("/")
|
return redirect("/")
|
||||||
|
|
||||||
status = form.save(commit=False)
|
status = form.save(request)
|
||||||
status.raise_not_editable(request.user)
|
|
||||||
# save the plain, unformatted version of the status for future editing
|
# save the plain, unformatted version of the status for future editing
|
||||||
status.raw_content = status.content
|
status.raw_content = status.content
|
||||||
if hasattr(status, "quote"):
|
if hasattr(status, "quote"):
|
||||||
|
@ -167,7 +164,6 @@ def edit_readthrough(request):
|
||||||
"""can't use the form because the dates are too finnicky"""
|
"""can't use the form because the dates are too finnicky"""
|
||||||
# TODO: remove this, it duplicates the code in the ReadThrough view
|
# TODO: remove this, it duplicates the code in the ReadThrough view
|
||||||
readthrough = get_object_or_404(models.ReadThrough, id=request.POST.get("id"))
|
readthrough = get_object_or_404(models.ReadThrough, id=request.POST.get("id"))
|
||||||
readthrough.raise_not_editable(request.user)
|
|
||||||
|
|
||||||
readthrough.start_date = load_date_in_user_tz_as_utc(
|
readthrough.start_date = load_date_in_user_tz_as_utc(
|
||||||
request.POST.get("start_date"), request.user
|
request.POST.get("start_date"), request.user
|
||||||
|
|
Loading…
Reference in a new issue