Skip to content

Commit

Permalink
Merge pull request #973 from ae-utbm/taiste
Browse files Browse the repository at this point in the history
Better counter, product management improvement, better form style and custom auth backend
  • Loading branch information
imperosol authored Dec 27, 2024
2 parents b773a05 + 2f9e5bf commit 673c427
Show file tree
Hide file tree
Showing 51 changed files with 3,166 additions and 1,406 deletions.
33 changes: 15 additions & 18 deletions com/templates/com/news_list.jinja
Original file line number Diff line number Diff line change
Expand Up @@ -136,25 +136,22 @@ type="EVENT").order_by('dates__start_date') %}
<div id="birthdays">
<div id="birthdays_title">{% trans %}Birthdays{% endtrans %}</div>
<div id="birthdays_content">
{% if user.is_subscribed %}
{# Cache request for 1 hour #}
{% cache 3600 "birthdays" %}
<ul class="birthdays_year">
{% for d in birthdays.dates('date_of_birth', 'year', 'DESC') %}
<li>
{% trans age=timezone.now().year - d.year %}{{ age }} year old{% endtrans %}
<ul>
{% for u in birthdays.filter(date_of_birth__year=d.year) %}
<li><a href="{{ u.get_absolute_url() }}">{{ u.get_short_name() }}</a></li>
{% endfor %}
</ul>
</li>
{% endfor %}
</ul>
{% endcache %}
{% else %}
{%- if user.is_subscribed -%}
<ul class="birthdays_year">
{%- for year, users in birthdays -%}
<li>
{% trans age=timezone.now().year - year %}{{ age }} year old{% endtrans %}
<ul>
{%- for u in users -%}
<li><a href="{{ u.get_absolute_url() }}">{{ u.get_short_name() }}</a></li>
{%- endfor -%}
</ul>
</li>
{%- endfor -%}
</ul>
{%- else -%}
<p>{% trans %}You need an up to date subscription to access this content{% endtrans %}</p>
{% endif %}
{%- endif -%}
</div>
</div>
</div>
Expand Down
7 changes: 4 additions & 3 deletions com/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
# Place - Suite 330, Boston, MA 02111-1307, USA.
#
#

import itertools
from datetime import timedelta
from smtplib import SMTPRecipientsRefused

Expand Down Expand Up @@ -374,13 +374,14 @@ def get_context_data(self, **kwargs):
kwargs = super().get_context_data(**kwargs)
kwargs["NewsDate"] = NewsDate
kwargs["timedelta"] = timedelta
kwargs["birthdays"] = (
kwargs["birthdays"] = itertools.groupby(
User.objects.filter(
date_of_birth__month=localdate().month,
date_of_birth__day=localdate().day,
)
.filter(role__in=["STUDENT", "FORMER STUDENT"])
.order_by("-date_of_birth")
.order_by("-date_of_birth"),
key=lambda u: u.date_of_birth.year,
)
return kwargs

Expand Down
42 changes: 42 additions & 0 deletions core/auth_backends.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
from __future__ import annotations

from typing import TYPE_CHECKING

from django.conf import settings
from django.contrib.auth.backends import ModelBackend
from django.contrib.auth.models import Permission

from core.models import Group

if TYPE_CHECKING:
from core.models import User


class SithModelBackend(ModelBackend):
"""Custom auth backend for the Sith.
In fact, it's the exact same backend as `django.contrib.auth.backend.ModelBackend`,
with the exception that group permissions are fetched slightly differently.
Indeed, django tries by default to fetch the permissions associated
with all the `django.contrib.auth.models.Group` of a user ;
however, our User model overrides that, so the actual linked group model
is [core.models.Group][].
Instead of having the relation `auth_perm --> auth_group <-- core_user`,
we have `auth_perm --> auth_group <-- core_group <-- core_user`.
Thus, this backend make the small tweaks necessary to make
our custom models interact with the django auth.
"""

def _get_group_permissions(self, user_obj: User):
# union of querysets doesn't work if the queryset is ordered.
# The empty `order_by` here are actually there to *remove*
# any default ordering defined in managers or model Meta
groups = user_obj.groups.order_by()
if user_obj.is_subscribed:
groups = groups.union(
Group.objects.filter(pk=settings.SITH_GROUP_SUBSCRIBERS_ID).order_by()
)
return Permission.objects.filter(
group__group__in=groups.values_list("pk", flat=True)
)
170 changes: 128 additions & 42 deletions core/management/commands/populate.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,14 +23,15 @@
from datetime import date, timedelta
from io import StringIO
from pathlib import Path
from typing import ClassVar
from typing import ClassVar, NamedTuple

from django.conf import settings
from django.contrib.auth.models import Permission
from django.contrib.sites.models import Site
from django.core.management import call_command
from django.core.management.base import BaseCommand
from django.db import connection
from django.db.models import Q
from django.utils import timezone
from django.utils.timezone import localdate
from PIL import Image
Expand All @@ -56,6 +57,18 @@
from subscription.models import Subscription


class PopulatedGroups(NamedTuple):
root: Group
public: Group
subscribers: Group
old_subscribers: Group
sas_admin: Group
com_admin: Group
counter_admin: Group
accounting_admin: Group
pedagogy_admin: Group


class Command(BaseCommand):
ROOT_PATH: ClassVar[Path] = Path(__file__).parent.parent.parent.parent
SAS_FIXTURE_PATH: ClassVar[Path] = (
Expand All @@ -79,25 +92,7 @@ def handle(self, *args, **options):

Sith.objects.create(weekmail_destinations="[email protected] [email protected]")
Site.objects.create(domain=settings.SITH_URL, name=settings.SITH_NAME)

root_group = Group.objects.create(name="Root")
public_group = Group.objects.create(name="Public")
subscribers = Group.objects.create(name="Subscribers")
old_subscribers = Group.objects.create(name="Old subscribers")
Group.objects.create(name="Accounting admin")
Group.objects.create(name="Communication admin")
Group.objects.create(name="Counter admin")
Group.objects.create(name="Banned from buying alcohol")
Group.objects.create(name="Banned from counters")
Group.objects.create(name="Banned to subscribe")
Group.objects.create(name="SAS admin")
Group.objects.create(name="Forum admin")
Group.objects.create(name="Pedagogy admin")
self.reset_index("core", "auth")

change_billing = Permission.objects.get(codename="change_billinginfo")
add_billing = Permission.objects.get(codename="add_billinginfo")
root_group.permissions.add(change_billing, add_billing)
groups = self._create_groups()

root = User.objects.create_superuser(
id=0,
Expand Down Expand Up @@ -155,7 +150,7 @@ def handle(self, *args, **options):
Counter.edit_groups.through.objects.bulk_create(bar_groups)
self.reset_index("counter")

subscribers.viewable_files.add(home_root, club_root)
groups.subscribers.viewable_files.add(home_root, club_root)

Weekmail().save()

Expand Down Expand Up @@ -260,21 +255,11 @@ def handle(self, *args, **options):
)
User.groups.through.objects.bulk_create(
[
User.groups.through(
group_id=settings.SITH_GROUP_COUNTER_ADMIN_ID, user=counter
),
User.groups.through(
group_id=settings.SITH_GROUP_ACCOUNTING_ADMIN_ID, user=comptable
),
User.groups.through(
group_id=settings.SITH_GROUP_COM_ADMIN_ID, user=comunity
),
User.groups.through(
group_id=settings.SITH_GROUP_PEDAGOGY_ADMIN_ID, user=tutu
),
User.groups.through(
group_id=settings.SITH_GROUP_SAS_ADMIN_ID, user=skia
),
User.groups.through(group=groups.counter_admin, user=counter),
User.groups.through(group=groups.accounting_admin, user=comptable),
User.groups.through(group=groups.com_admin, user=comunity),
User.groups.through(group=groups.pedagogy_admin, user=tutu),
User.groups.through(group=groups.sas_admin, user=skia),
]
)
for user in richard, sli, krophil, skia:
Expand Down Expand Up @@ -335,7 +320,7 @@ def handle(self, *args, **options):
content="Fonctionnement de la laverie",
)

public_group.viewable_page.set(
groups.public.viewable_page.set(
[syntax_page, services_page, index_page, laundry_page]
)

Expand Down Expand Up @@ -512,8 +497,10 @@ def handle(self, *args, **options):
club=main_club,
limit_age=18,
)
subscribers.products.add(cotis, cotis2, refill, barb, cble, cors, carolus)
old_subscribers.products.add(cotis, cotis2)
groups.subscribers.products.add(
cotis, cotis2, refill, barb, cble, cors, carolus
)
groups.old_subscribers.products.add(cotis, cotis2)

mde = Counter.objects.get(name="MDE")
mde.products.add(barb, cble, cons, dcons)
Expand Down Expand Up @@ -616,10 +603,10 @@ def handle(self, *args, **options):
start_date="1942-06-12 10:28:45+01",
end_date="7942-06-12 10:28:45+01",
)
el.view_groups.add(public_group)
el.view_groups.add(groups.public)
el.edit_groups.add(ae_board_group)
el.candidature_groups.add(subscribers)
el.vote_groups.add(subscribers)
el.candidature_groups.add(groups.subscribers)
el.vote_groups.add(groups.subscribers)
liste = ElectionList.objects.create(title="Candidature Libre", election=el)
listeT = ElectionList.objects.create(title="Troll", election=el)
pres = Role.objects.create(
Expand Down Expand Up @@ -898,3 +885,102 @@ def _create_subscription(
start=s.subscription_start,
)
s.save()

def _create_groups(self) -> PopulatedGroups:
perms = Permission.objects.all()

root_group = Group.objects.create(name="Root")
root_group.permissions.add(*list(perms.values_list("pk", flat=True)))
# public has no permission.
# Its purpose is not to link users to permissions,
# but to other objects (like products)
public_group = Group.objects.create(name="Public")

subscribers = Group.objects.create(name="Subscribers")
old_subscribers = Group.objects.create(name="Old subscribers")
old_subscribers.permissions.add(
*list(
perms.filter(
codename__in=[
"view_user",
"view_picture",
"view_album",
"view_peoplepicturerelation",
"add_peoplepicturerelation",
]
)
)
)
accounting_admin = Group.objects.create(name="Accounting admin")
accounting_admin.permissions.add(
*list(
perms.filter(
Q(content_type__app_label="accounting")
| Q(
codename__in=[
"view_customer",
"view_product",
"change_product",
"add_product",
"view_producttype",
"change_producttype",
"add_producttype",
"delete_selling",
]
)
).values_list("pk", flat=True)
)
)
com_admin = Group.objects.create(name="Communication admin")
com_admin.permissions.add(
*list(
perms.filter(content_type__app_label="com").values_list("pk", flat=True)
)
)
counter_admin = Group.objects.create(name="Counter admin")
counter_admin.permissions.add(
*list(
perms.filter(
Q(content_type__app_label__in=["counter", "launderette"])
& ~Q(codename__in=["delete_product", "delete_producttype"])
)
)
)
Group.objects.create(name="Banned from buying alcohol")
Group.objects.create(name="Banned from counters")
Group.objects.create(name="Banned to subscribe")
sas_admin = Group.objects.create(name="SAS admin")
sas_admin.permissions.add(
*list(
perms.filter(content_type__app_label="sas").values_list("pk", flat=True)
)
)
forum_admin = Group.objects.create(name="Forum admin")
forum_admin.permissions.add(
*list(
perms.filter(content_type__app_label="forum").values_list(
"pk", flat=True
)
)
)
pedagogy_admin = Group.objects.create(name="Pedagogy admin")
pedagogy_admin.permissions.add(
*list(
perms.filter(content_type__app_label="pedagogy").values_list(
"pk", flat=True
)
)
)
self.reset_index("core", "auth")

return PopulatedGroups(
root=root_group,
public=public_group,
subscribers=subscribers,
old_subscribers=old_subscribers,
com_admin=com_admin,
counter_admin=counter_admin,
accounting_admin=accounting_admin,
sas_admin=sas_admin,
pedagogy_admin=pedagogy_admin,
)
8 changes: 0 additions & 8 deletions core/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -578,14 +578,6 @@ def get_display_name(self) -> str:
return "%s (%s)" % (self.get_full_name(), self.nick_name)
return self.get_full_name()

def get_age(self):
"""Returns the age."""
today = timezone.now()
born = self.date_of_birth
return (
today.year - born.year - ((today.month, today.day) < (born.month, born.day))
)

def get_family(
self,
godfathers_depth: NonNegativeInt = 4,
Expand Down
5 changes: 4 additions & 1 deletion core/static/bundled/utils/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,13 @@ type PaginatedEndpoint<T> = <ThrowOnError extends boolean = false>(

// TODO : If one day a test workflow is made for JS in this project
// please test this function. A all cost.
/**
* Load complete dataset from paginated routes.
*/
export const paginated = async <T>(
endpoint: PaginatedEndpoint<T>,
options?: PaginatedRequest,
) => {
): Promise<T[]> => {
const maxPerPage = 199;
const queryParams = options ?? {};
queryParams.query = queryParams.query ?? {};
Expand Down
Loading

0 comments on commit 673c427

Please sign in to comment.