mirror of
https://github.com/ae-utbm/sith.git
synced 2026-09-18 10:14:24 +00:00
Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
62b49240d1 |
@@ -18,7 +18,7 @@ class Migration(migrations.Migration):
|
|||||||
"Groups that are automatically given or removed "
|
"Groups that are automatically given or removed "
|
||||||
"to user receiving or losing this club role"
|
"to user receiving or losing this club role"
|
||||||
),
|
),
|
||||||
related_name="club_roles",
|
related_name="linked_roles",
|
||||||
to="core.group",
|
to="core.group",
|
||||||
verbose_name="Linked groups",
|
verbose_name="Linked groups",
|
||||||
),
|
),
|
||||||
|
|||||||
+4
-55
@@ -1,16 +1,15 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
import typing
|
from typing import TYPE_CHECKING
|
||||||
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.contrib.auth.backends import ModelBackend
|
from django.contrib.auth.backends import ModelBackend
|
||||||
from django.contrib.auth.models import Permission
|
from django.contrib.auth.models import Permission
|
||||||
from django.db.models import Exists, OuterRef, Q, QuerySet
|
|
||||||
|
|
||||||
from core.models import Group, User
|
from core.models import Group
|
||||||
|
|
||||||
if typing.TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from django.db.models.base import Model
|
from core.models import User
|
||||||
|
|
||||||
|
|
||||||
class SithModelBackend(ModelBackend):
|
class SithModelBackend(ModelBackend):
|
||||||
@@ -41,53 +40,3 @@ class SithModelBackend(ModelBackend):
|
|||||||
return Permission.objects.filter(
|
return Permission.objects.filter(
|
||||||
group__group__in=groups.values_list("pk", flat=True)
|
group__group__in=groups.values_list("pk", flat=True)
|
||||||
)
|
)
|
||||||
|
|
||||||
@typing.override
|
|
||||||
def with_perm(
|
|
||||||
self,
|
|
||||||
perm: str | Permission,
|
|
||||||
is_active: bool | None = True,
|
|
||||||
include_superusers: bool = False,
|
|
||||||
obj: Model | None = None,
|
|
||||||
) -> QuerySet[User]:
|
|
||||||
"""Return users that have permission "perm".
|
|
||||||
|
|
||||||
Contrary to the base django method, superusers aren't included in the
|
|
||||||
result.
|
|
||||||
This is because the OR operation to include superusers in the query result
|
|
||||||
utterly destroy the query performances on postgres
|
|
||||||
(it makes it like 1000x slower, and I'm not even kidding).
|
|
||||||
To overcome that, we could use a UNION instead, but then we wouldn't
|
|
||||||
be able to perform further filter operations on the queryset.
|
|
||||||
Thus, the `include_superusers` argument is not used at all.
|
|
||||||
|
|
||||||
Because of that, it is useless to set `include_superusers`,
|
|
||||||
as it will be silently ignored.
|
|
||||||
The only reason it's still there is not to break the interface
|
|
||||||
of the base class.
|
|
||||||
"""
|
|
||||||
if isinstance(perm, str):
|
|
||||||
try:
|
|
||||||
app_label, codename = perm.split(".")
|
|
||||||
except ValueError as e:
|
|
||||||
raise ValueError(
|
|
||||||
"Permission name should be in the form "
|
|
||||||
"app_label.permission_codename."
|
|
||||||
) from e
|
|
||||||
permission_q = Q(codename=codename, content_type__app_label=app_label)
|
|
||||||
elif isinstance(perm, Permission):
|
|
||||||
permission_q = Q(pk=perm.pk)
|
|
||||||
else:
|
|
||||||
raise TypeError(
|
|
||||||
"The `perm` argument must be a string or a permission instance."
|
|
||||||
)
|
|
||||||
|
|
||||||
user_q = Exists(
|
|
||||||
Permission.objects.filter(
|
|
||||||
Q(group__group__users=OuterRef("pk")) | Q(user=OuterRef("pk")),
|
|
||||||
permission_q,
|
|
||||||
)
|
|
||||||
)
|
|
||||||
if is_active is not None:
|
|
||||||
user_q &= Q(is_active=is_active)
|
|
||||||
return User.objects.filter(user_q)
|
|
||||||
|
|||||||
@@ -747,7 +747,6 @@ class Command(BaseCommand):
|
|||||||
"add_subscription",
|
"add_subscription",
|
||||||
"add_membership",
|
"add_membership",
|
||||||
"view_hidden_user",
|
"view_hidden_user",
|
||||||
"add_refilling",
|
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,27 +0,0 @@
|
|||||||
import pytest
|
|
||||||
from django.contrib.auth.models import Permission
|
|
||||||
from model_bakery import baker
|
|
||||||
|
|
||||||
from core.models import Group, User
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.django_db
|
|
||||||
def test_with_perm():
|
|
||||||
"""Test that `SithModelBackend.with_perm` works as intended."""
|
|
||||||
perms = baker.make(Permission, _quantity=4)
|
|
||||||
groups = baker.make(Group, _quantity=2)
|
|
||||||
groups[0].permissions.set(perms[0:2])
|
|
||||||
groups[1].permissions.set(perms[2:4])
|
|
||||||
users = [
|
|
||||||
baker.make(User),
|
|
||||||
baker.make(User, groups=[groups[0]]),
|
|
||||||
baker.make(User, groups=[groups[1]]),
|
|
||||||
baker.make(User, user_permissions=[perms[0]]),
|
|
||||||
baker.make(User, user_permissions=[perms[2]]),
|
|
||||||
baker.make(User, groups=[groups[1]], user_permissions=[perms[0]]),
|
|
||||||
]
|
|
||||||
|
|
||||||
expected = [users[1], users[3], users[5]]
|
|
||||||
assert list(User.objects.with_perm(perms[0])) == expected
|
|
||||||
str_repr = f"{perms[0].content_type.app_label}.{perms[0].codename}"
|
|
||||||
assert list(User.objects.with_perm(str_repr)) == expected
|
|
||||||
@@ -11,7 +11,7 @@ class Migration(migrations.Migration):
|
|||||||
model_name="permanency",
|
model_name="permanency",
|
||||||
name="end",
|
name="end",
|
||||||
field=models.DateTimeField(
|
field=models.DateTimeField(
|
||||||
db_index=True, verbose_name="end date", null=True
|
db_index=True, verbose_name="end date", null=True, blank=True
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -6,9 +6,7 @@ from django.db import migrations, models
|
|||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
class Migration(migrations.Migration):
|
||||||
dependencies = [
|
dependencies = [("counter", "0018_producttype_priority")]
|
||||||
("counter", "0018_producttype_priority"),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
operations = [
|
||||||
migrations.AlterModelOptions(
|
migrations.AlterModelOptions(
|
||||||
|
|||||||
@@ -6,9 +6,7 @@ import counter.fields
|
|||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
class Migration(migrations.Migration):
|
||||||
dependencies = [
|
dependencies = [("counter", "0019_billinginfo")]
|
||||||
("counter", "0019_billinginfo"),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
operations = [
|
||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
|
|||||||
+6
-11
@@ -669,18 +669,13 @@ class Counter(models.Model):
|
|||||||
"""Update the barman activity to prevent timeout."""
|
"""Update the barman activity to prevent timeout."""
|
||||||
self.permanencies.filter(end=None).update(activity=timezone.now())
|
self.permanencies.filter(end=None).update(activity=timezone.now())
|
||||||
|
|
||||||
@cached_property
|
|
||||||
def can_refill(self) -> bool:
|
def can_refill(self) -> bool:
|
||||||
"""Show if the counter authorize the refilling with physic money.
|
"""Show if the counter authorize the refilling with physic money."""
|
||||||
|
if self.type != "BAR":
|
||||||
Refills are authorized if a user having the required permission
|
return False
|
||||||
is currently logged in.
|
# at least one of the barmen is in the AE board
|
||||||
"""
|
ae = Club.objects.get(id=settings.SITH_MAIN_CLUB_ID)
|
||||||
return self.type == "BAR" and (
|
return any(ae.get_membership_for(barman) for barman in self.barmen_list)
|
||||||
User.objects.with_perm("counter.add_refilling")
|
|
||||||
.filter(id__in=[u.id for u in self.barmen_list])
|
|
||||||
.exists()
|
|
||||||
)
|
|
||||||
|
|
||||||
def get_top_barmen(self) -> QuerySet:
|
def get_top_barmen(self) -> QuerySet:
|
||||||
"""Return a QuerySet querying the office hours stats of all the barmen of all time
|
"""Return a QuerySet querying the office hours stats of all the barmen of all time
|
||||||
|
|||||||
@@ -108,13 +108,6 @@ class TestFullClickBase(TestCase):
|
|||||||
|
|
||||||
|
|
||||||
class TestRefilling(TestFullClickBase):
|
class TestRefilling(TestFullClickBase):
|
||||||
@classmethod
|
|
||||||
def setUpTestData(cls):
|
|
||||||
super().setUpTestData()
|
|
||||||
cls.board_admin.user_permissions.add(
|
|
||||||
Permission.objects.get(codename="add_refilling")
|
|
||||||
)
|
|
||||||
|
|
||||||
def login_in_bar(self, barmen: User | None = None):
|
def login_in_bar(self, barmen: User | None = None):
|
||||||
used_barman = barmen if barmen is not None else self.board_admin
|
used_barman = barmen if barmen is not None else self.board_admin
|
||||||
self.client.post(
|
self.client.post(
|
||||||
@@ -154,7 +147,7 @@ class TestRefilling(TestFullClickBase):
|
|||||||
assert self.updated_amount(self.customer) == 0
|
assert self.updated_amount(self.customer) == 0
|
||||||
|
|
||||||
def test_refilling_no_refer_fail(self):
|
def test_refilling_no_refer_fail(self):
|
||||||
"""Check that the refill fails if the HTTP_REFERER header is missing"""
|
"""Check that the refill fails is the HTTP_REFERER header is missing"""
|
||||||
|
|
||||||
def refill():
|
def refill():
|
||||||
return self.client.post(
|
return self.client.post(
|
||||||
|
|||||||
@@ -204,7 +204,7 @@ class CounterClick(
|
|||||||
res["student_card_fragment"] = StudentCardFormFragment.as_fragment()(
|
res["student_card_fragment"] = StudentCardFormFragment.as_fragment()(
|
||||||
self.request, customer=self.customer
|
self.request, customer=self.customer
|
||||||
)
|
)
|
||||||
if self.object.can_refill:
|
if self.object.can_refill():
|
||||||
res["refilling_fragment"] = RefillingCreateView.as_fragment()(
|
res["refilling_fragment"] = RefillingCreateView.as_fragment()(
|
||||||
self.request, customer=self.customer, counter=self.object
|
self.request, customer=self.customer, counter=self.object
|
||||||
)
|
)
|
||||||
@@ -250,7 +250,7 @@ class RefillingCreateView(FragmentMixin, CreateView):
|
|||||||
if not (
|
if not (
|
||||||
request.barmen
|
request.barmen
|
||||||
and request.barmen.issubset(self.counter.barmen_list)
|
and request.barmen.issubset(self.counter.barmen_list)
|
||||||
and self.counter.can_refill
|
and self.counter.can_refill()
|
||||||
):
|
):
|
||||||
raise PermissionDenied
|
raise PermissionDenied
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user