Better usage of cache for groups and clubs related operations (#634)

* Better usage of cache for group retrieval

* Cache clearing on object deletion or update

* replace signals by save and delete override

* add is_anonymous check in is_owned_by

Add in many is_owned_by(self, user) methods that user is not anonymous. Since many of those functions do db queries, this should reduce a little bit the load of the db.

* Stricter usage of User.is_in_group

Constrain the parameters that can be passed to the function to make sure only a str or an int can be used. Also force to explicitly specify if the group id or the group name is used.

* write test and correct bugs

* remove forgotten populate commands

* Correct test
This commit is contained in:
thomas girod
2023-05-02 12:36:59 +02:00
committed by GitHub
parent 96dede5077
commit ef968f3673
50 changed files with 1315 additions and 699 deletions

View File

@ -50,7 +50,9 @@ class Sith(models.Model):
version = utils.get_git_revision_short_hash()
def is_owned_by(self, user):
return user.is_in_group(settings.SITH_GROUP_COM_ADMIN_ID)
if user.is_anonymous:
return False
return user.is_com_admin
def __str__(self):
return "⛩ Sith ⛩"
@ -92,13 +94,15 @@ class News(models.Model):
)
def is_owned_by(self, user):
return user.is_in_group(settings.SITH_GROUP_COM_ADMIN_ID) or user == self.author
if user.is_anonymous:
return False
return user.is_com_admin or user == self.author
def can_be_edited_by(self, user):
return user.is_in_group(settings.SITH_GROUP_COM_ADMIN_ID)
return user.is_com_admin
def can_be_viewed_by(self, user):
return self.is_moderated or user.is_in_group(settings.SITH_GROUP_COM_ADMIN_ID)
return self.is_moderated or user.is_com_admin
def get_absolute_url(self):
return reverse("com:news_detail", kwargs={"news_id": self.id})
@ -243,7 +247,9 @@ class Weekmail(models.Model):
return "Weekmail %s (sent: %s) - %s" % (self.id, self.sent, self.title)
def is_owned_by(self, user):
return user.is_in_group(settings.SITH_GROUP_COM_ADMIN_ID)
if user.is_anonymous:
return False
return user.is_com_admin
class WeekmailArticle(models.Model):
@ -271,7 +277,9 @@ class WeekmailArticle(models.Model):
rank = models.IntegerField(_("rank"), default=-1)
def is_owned_by(self, user):
return user.is_in_group(settings.SITH_GROUP_COM_ADMIN_ID)
if user.is_anonymous:
return False
return user.is_com_admin
def __str__(self):
return "%s - %s (%s)" % (self.title, self.author, self.club)
@ -287,7 +295,9 @@ class Screen(models.Model):
)
def is_owned_by(self, user):
return user.is_in_group(settings.SITH_GROUP_COM_ADMIN_ID)
if user.is_anonymous:
return False
return user.is_com_admin
def __str__(self):
return "%s" % (self.name)
@ -340,12 +350,12 @@ class Poster(models.Model):
raise ValidationError(_("Begin date should be before end date"))
def is_owned_by(self, user):
return user.is_in_group(
settings.SITH_GROUP_COM_ADMIN_ID
) or Club.objects.filter(id__in=user.clubs_with_rights)
if user.is_anonymous:
return False
return user.is_com_admin or len(user.clubs_with_rights) > 0
def can_be_moderated_by(self, user):
return user.is_in_group(settings.SITH_GROUP_COM_ADMIN_ID)
return user.is_com_admin
def get_display_name(self):
return self.club.get_display_name()

View File

@ -35,7 +35,7 @@
<p>{% trans %}Author: {% endtrans %}{{ user_profile_link(news.author) }}</p>
{% if news.moderator %}
<p>{% trans %}Moderator: {% endtrans %}{{ user_profile_link(news.moderator) }}</p>
{% elif user.is_in_group(settings.SITH_GROUP_COM_ADMIN_ID) %}
{% elif user.is_com_admin %}
<p> <a href="{{ url('com:news_moderate', news_id=news.id) }}">{% trans %}Moderate{% endtrans %}</a></p>
{% endif %}
{% if user.can_edit(news) %}

View File

@ -49,7 +49,7 @@
<p>{{ form.club.errors }}<label for="{{ form.club.name }}">{{ form.club.label }}</label> {{ form.club }}</p>
<p>{{ form.summary.errors }}<label for="{{ form.summary.name }}">{{ form.summary.label }}</label> {{ form.summary }}</p>
<p>{{ form.content.errors }}<label for="{{ form.content.name }}">{{ form.content.label }}</label> {{ form.content }}</p>
{% if user.is_in_group(settings.SITH_GROUP_COM_ADMIN_ID) %}
{% if user.is_com_admin %}
<p>{{ form.automoderation.errors }}<label for="{{ form.automoderation.name }}">{{ form.automoderation.label }}</label>
{{ form.automoderation }}</p>
{% endif %}

View File

@ -6,7 +6,7 @@
{% endblock %}
{% block content %}
{% if user.is_in_group(settings.SITH_GROUP_COM_ADMIN_ID) %}
{% if user.is_com_admin %}
<div id="news_admin">
<a class="button" href="{{ url('com:news_admin_list') }}">{% trans %}Administrate news{% endtrans %}</a>
</div>

View File

@ -13,16 +13,18 @@
# OR WITHIN THE LOCAL FILE "LICENSE"
#
#
from django.core.files.uploadedfile import SimpleUploadedFile
from django.test import TestCase
from django.conf import settings
from django.urls import reverse
from django.core.management import call_command
from django.utils import html
from django.utils.timezone import localtime, now
from django.utils.translation import gettext as _
from core.models import User, RealGroup
from club.models import Club, Membership
from com.models import Sith, News, Weekmail, WeekmailArticle, Poster
from core.models import User, RealGroup, AnonymousUser
class ComAlertTest(TestCase):
@ -110,3 +112,102 @@ class ComTest(TestCase):
_("You need an up to date subscription to access this content")
),
)
class SithTest(TestCase):
def test_sith_owner(self):
"""
Test that the sith instance is owned by com admins
and nobody else
"""
sith: Sith = Sith.objects.first()
com_admin = User.objects.get(username="comunity")
self.assertTrue(sith.is_owned_by(com_admin))
anonymous = AnonymousUser()
self.assertFalse(sith.is_owned_by(anonymous))
sli = User.objects.get(username="sli")
self.assertFalse(sith.is_owned_by(sli))
class NewsTest(TestCase):
@classmethod
def setUpTestData(cls):
cls.com_admin = User.objects.get(username="comunity")
new = News.objects.create(
title="dummy new",
summary="This is a dummy new",
content="Look at that beautiful dummy new",
author=User.objects.get(username="subscriber"),
club=Club.objects.first(),
)
cls.new = new
cls.author = new.author
cls.sli = User.objects.get(username="sli")
cls.anonymous = AnonymousUser()
def test_news_owner(self):
"""
Test that news are owned by com admins
or by their author but nobody else
"""
self.assertTrue(self.new.is_owned_by(self.com_admin))
self.assertTrue(self.new.is_owned_by(self.author))
self.assertFalse(self.new.is_owned_by(self.anonymous))
self.assertFalse(self.new.is_owned_by(self.sli))
class WeekmailArticleTest(TestCase):
@classmethod
def setUpTestData(cls):
cls.com_admin = User.objects.get(username="comunity")
author = User.objects.get(username="subscriber")
cls.article = WeekmailArticle.objects.create(
weekmail=Weekmail.objects.create(),
author=author,
title="title",
content="Some content",
club=Club.objects.first(),
)
cls.author = author
cls.sli = User.objects.get(username="sli")
cls.anonymous = AnonymousUser()
def test_weekmail_owner(self):
"""
Test that weekmails are owned only by com admins
"""
self.assertTrue(self.article.is_owned_by(self.com_admin))
self.assertFalse(self.article.is_owned_by(self.author))
self.assertFalse(self.article.is_owned_by(self.anonymous))
self.assertFalse(self.article.is_owned_by(self.sli))
class PosterTest(TestCase):
@classmethod
def setUpTestData(cls):
cls.com_admin = User.objects.get(username="comunity")
cls.poster = Poster.objects.create(
name="dummy",
file=SimpleUploadedFile("dummy.jpg", b"azertyuiop"),
club=Club.objects.first(),
date_begin=localtime(now()),
)
cls.sli = User.objects.get(username="sli")
cls.sli.memberships.all().delete()
Membership(user=cls.sli, club=Club.objects.first(), role=5).save()
cls.susbcriber = User.objects.get(username="subscriber")
cls.anonymous = AnonymousUser()
def test_poster_owner(self):
"""
Test that poster are owned by com admins and board members in clubs
"""
self.assertTrue(self.poster.is_owned_by(self.com_admin))
self.assertFalse(self.poster.is_owned_by(self.anonymous))
self.assertFalse(self.poster.is_owned_by(self.susbcriber))
self.assertTrue(self.poster.is_owned_by(self.sli))

View File

@ -146,7 +146,7 @@ class ComTabsMixin(TabedViewMixin):
class IsComAdminMixin(View):
def dispatch(self, request, *args, **kwargs):
if not (request.user.is_in_group(settings.SITH_GROUP_COM_ADMIN_ID)):
if not request.user.is_com_admin:
raise PermissionDenied
return super(IsComAdminMixin, self).dispatch(request, *args, **kwargs)
@ -283,9 +283,7 @@ class NewsEditView(CanEditMixin, UpdateView):
def form_valid(self, form):
self.object = form.save()
if form.cleaned_data["automoderation"] and self.request.user.is_in_group(
settings.SITH_GROUP_COM_ADMIN_ID
):
if form.cleaned_data["automoderation"] and self.request.user.is_com_admin:
self.object.moderator = self.request.user
self.object.is_moderated = True
self.object.save()
@ -333,9 +331,7 @@ class NewsCreateView(CanCreateMixin, CreateView):
def form_valid(self, form):
self.object = form.save()
if form.cleaned_data["automoderation"] and self.request.user.is_in_group(
settings.SITH_GROUP_COM_ADMIN_ID
):
if form.cleaned_data["automoderation"] and self.request.user.is_com_admin:
self.object.moderator = self.request.user
self.object.is_moderated = True
self.object.save()
@ -617,10 +613,7 @@ class MailingListAdminView(ComTabsMixin, ListView):
current_tab = "mailings"
def dispatch(self, request, *args, **kwargs):
if not (
request.user.is_in_group(settings.SITH_GROUP_COM_ADMIN_ID)
or request.user.is_root
):
if not (request.user.is_com_admin or request.user.is_root):
raise PermissionDenied
return super(MailingListAdminView, self).dispatch(request, *args, **kwargs)