diff --git a/bookwyrm/forms.py b/bookwyrm/forms.py index 23063ff7c..b9b93694c 100644 --- a/bookwyrm/forms.py +++ b/bookwyrm/forms.py @@ -228,7 +228,7 @@ class ExpiryWidget(widgets.Select): elif selected_string == "forever": return None else: - return selected_string # "This will raise + return selected_string # This will raise return timezone.now() + interval diff --git a/bookwyrm/models/base_model.py b/bookwyrm/models/base_model.py index aa174a143..ca32521a3 100644 --- a/bookwyrm/models/base_model.py +++ b/bookwyrm/models/base_model.py @@ -1,8 +1,11 @@ """ base model with default fields """ import base64 from Crypto import Random + +from django.core.exceptions import PermissionDenied from django.db import models from django.dispatch import receiver +from django.http import Http404 from django.utils.translation import gettext_lazy as _ from bookwyrm.settings import DOMAIN @@ -48,26 +51,26 @@ class BookWyrmModel(models.Model): """how to link to this object in the local app""" return self.get_remote_id().replace(f"https://{DOMAIN}", "") - def visible_to_user(self, viewer): + def raise_visible_to_user(self, viewer): """is a user authorized to view an object?""" # make sure this is an object with privacy owned by a user if not hasattr(self, "user") or not hasattr(self, "privacy"): - return None + return # viewer can't see it if the object's owner blocked them if viewer in self.user.blocks.all(): - return False + raise Http404() # you can see your own posts and any public or unlisted posts if viewer == self.user or self.privacy in ["public", "unlisted"]: - return True + return # you can see the followers only posts of people you follow if ( self.privacy == "followers" and self.user.followers.filter(id=viewer.id).first() ): - return True + return # you can see dms you are tagged in if hasattr(self, "mention_users"): @@ -75,8 +78,32 @@ class BookWyrmModel(models.Model): self.privacy == "direct" and self.mention_users.filter(id=viewer.id).first() ): - return True - return False + return + raise Http404() + + def raise_not_editable(self, viewer): + """does this user have permission to edit this object? liable to be overwritten + by models that inherit this base model class""" + if not hasattr(self, "user"): + return + + # generally moderators shouldn't be able to edit other people's stuff + if self.user == viewer: + return + + raise PermissionDenied() + + def raise_not_deletable(self, viewer): + """does this user have permission to delete this object? liable to be + overwritten by models that inherit this base model class""" + if not hasattr(self, "user"): + return + + # but generally moderators can delete other people's stuff + if self.user == viewer or viewer.has_perm("moderate_post"): + return + + raise PermissionDenied() @receiver(models.signals.post_save) diff --git a/bookwyrm/models/list.py b/bookwyrm/models/list.py index 49fb53757..022a0d981 100644 --- a/bookwyrm/models/list.py +++ b/bookwyrm/models/list.py @@ -92,6 +92,12 @@ class ListItem(CollectionItemMixin, BookWyrmModel): notification_type="ADD", ) + def raise_not_deletable(self, viewer): + """the associated user OR the list owner can delete""" + if self.book_list.user == viewer: + return + super().raise_not_deletable(viewer) + class Meta: """A book may only be placed into a list once, and each order in the list may be used only once""" diff --git a/bookwyrm/models/shelf.py b/bookwyrm/models/shelf.py index 6f1344022..89ea9471d 100644 --- a/bookwyrm/models/shelf.py +++ b/bookwyrm/models/shelf.py @@ -1,5 +1,6 @@ """ puttin' books on shelves """ import re +from django.core.exceptions import PermissionDenied from django.db import models from django.utils import timezone @@ -57,6 +58,12 @@ class Shelf(OrderedCollectionMixin, BookWyrmModel): identifier = self.identifier or self.get_identifier() return f"{base_path}/books/{identifier}" + def raise_not_deletable(self, viewer): + """don't let anyone delete a default shelf""" + super().raise_not_deletable(viewer) + if not self.editable: + raise PermissionDenied() + class Meta: """user/shelf unqiueness""" diff --git a/bookwyrm/models/status.py b/bookwyrm/models/status.py index 3a0fad5e5..b62036788 100644 --- a/bookwyrm/models/status.py +++ b/bookwyrm/models/status.py @@ -3,6 +3,7 @@ from dataclasses import MISSING import re from django.apps import apps +from django.core.exceptions import PermissionDenied from django.core.validators import MaxValueValidator, MinValueValidator from django.db import models from django.dispatch import receiver @@ -187,6 +188,13 @@ class Status(OrderedCollectionPageMixin, BookWyrmModel): """json serialized activitypub class""" return self.to_activity_dataclass(pure=pure).serialize() + def raise_not_editable(self, viewer): + """certain types of status aren't editable""" + # first, the standard raise + super().raise_not_editable(viewer) + if isinstance(self, (GeneratedNote, ReviewRating)): + raise PermissionDenied() + class GeneratedNote(Status): """these are app-generated messages about user activity""" diff --git a/bookwyrm/templates/lists/list.html b/bookwyrm/templates/lists/list.html index 35014a7b6..dbee2f1f5 100644 --- a/bookwyrm/templates/lists/list.html +++ b/bookwyrm/templates/lists/list.html @@ -66,14 +66,14 @@
{% blocktrans with username=item.user.display_name user_path=item.user.local_path %}Added by {{ username }}{% endblocktrans %}
- {% if list.user == request.user or list.curation == 'open' and item.user == request.user %} + {% if list.user == request.user %} -