diff --git a/com/models.py b/com/models.py index 011e8900..85c2b63d 100644 --- a/com/models.py +++ b/com/models.py @@ -21,7 +21,7 @@ # Place - Suite 330, Boston, MA 02111-1307, USA. # # - +from typing import Self from django.conf import settings from django.core.exceptions import ValidationError @@ -55,13 +55,20 @@ class Sith(models.Model): class NewsQuerySet(models.QuerySet): - def moderated(self): + def moderated(self) -> Self: return self.filter(is_moderated=True) - def viewable_by(self, user: User): + def viewable_by(self, user: User) -> Self: + """Filter news that the given user can view. + + If the user has the `com.view_unmoderated_news` permission, + all news are viewable. + Else the viewable news are those that are either moderated + or authored by the user. + """ if user.has_perm("com.view_unmoderated_news"): return self - return self.moderated() + return self.filter(Q(is_moderated=True) | Q(author_id=user.id)) class News(models.Model): diff --git a/com/tests/test_models.py b/com/tests/test_models.py new file mode 100644 index 00000000..41be34ee --- /dev/null +++ b/com/tests/test_models.py @@ -0,0 +1,42 @@ +import itertools + +from django.contrib.auth.models import Permission +from django.test import TestCase +from model_bakery import baker + +from com.models import News +from core.models import User + + +class TestNewsViewableBy(TestCase): + @classmethod + def setUpTestData(cls): + News.objects.all().delete() + cls.users = baker.make(User, _quantity=3, _bulk_create=True) + # There are six news and six authors. + # Each author has one moderated and one non-moderated news + cls.news = baker.make( + News, + author=itertools.cycle(cls.users), + is_moderated=iter([True, True, True, False, False, False]), + _quantity=6, + _bulk_create=True, + ) + + def test_admin_can_view_everything(self): + """Test with a user that can view non moderated news.""" + user = baker.make( + User, + user_permissions=[Permission.objects.get(codename="view_unmoderated_news")], + ) + assert set(News.objects.viewable_by(user)) == set(self.news) + + def test_normal_user_can_view_moderated_and_self_news(self): + """Test that basic users can view moderated news and news they authored.""" + user = self.news[0].author + assert set(News.objects.viewable_by(user)) == { + self.news[0], + self.news[1], + self.news[2], + self.news[3], + }