diff --git a/club/admin.py b/club/admin.py index 04265245..0622cb16 100644 --- a/club/admin.py +++ b/club/admin.py @@ -19,8 +19,8 @@ from club.models import Club, Membership @admin.register(Club) class ClubAdmin(admin.ModelAdmin): - list_display = ("name", "unix_name", "parent", "is_active") - search_fields = ("name", "unix_name") + list_display = ("name", "slug_name", "parent", "is_active") + search_fields = ("name", "slug_name") autocomplete_fields = ( "parent", "board_group", diff --git a/club/migrations/0011_auto_20180426_2013.py b/club/migrations/0011_auto_20180426_2013.py index c10fe7b7..1dba79c2 100644 --- a/club/migrations/0011_auto_20180426_2013.py +++ b/club/migrations/0011_auto_20180426_2013.py @@ -1,10 +1,9 @@ from __future__ import unicode_literals import django.db.models.deletion +from django.conf import settings from django.db import migrations, models -import club.models - class Migration(migrations.Migration): dependencies = [("club", "0010_auto_20170912_2028")] @@ -15,7 +14,7 @@ class Migration(migrations.Migration): name="owner_group", field=models.ForeignKey( on_delete=django.db.models.deletion.CASCADE, - default=club.models.get_default_owner_group, + default=lambda: settings.SITH_ROOT_USER_ID, related_name="owned_club", to="core.Group", ), diff --git a/club/migrations/0014_alter_club_options_rename_unix_name_club_slug_name_and_more.py b/club/migrations/0014_alter_club_options_rename_unix_name_club_slug_name_and_more.py new file mode 100644 index 00000000..c6b4460f --- /dev/null +++ b/club/migrations/0014_alter_club_options_rename_unix_name_club_slug_name_and_more.py @@ -0,0 +1,75 @@ +# Generated by Django 4.2.17 on 2025-02-28 20:34 + +import django.db.models.deletion +from django.db import migrations, models + +import core.fields + + +class Migration(migrations.Migration): + dependencies = [ + ("core", "0044_alter_userban_options"), + ("club", "0013_alter_club_board_group_alter_club_members_group_and_more"), + ] + + operations = [ + migrations.AlterModelOptions(name="club", options={"ordering": ["name"]}), + migrations.RenameField( + model_name="club", + old_name="unix_name", + new_name="slug_name", + ), + migrations.AlterField( + model_name="club", + name="name", + field=models.CharField(unique=True, max_length=64, verbose_name="name"), + ), + migrations.AlterField( + model_name="club", + name="slug_name", + field=models.SlugField( + editable=False, max_length=30, unique=True, verbose_name="slug name" + ), + ), + migrations.AlterField( + model_name="club", + name="id", + field=models.AutoField( + auto_created=True, primary_key=True, serialize=False, verbose_name="ID" + ), + ), + migrations.AlterField( + model_name="club", + name="logo", + field=core.fields.ResizedImageField( + blank=True, + force_format="WEBP", + height=200, + null=True, + upload_to="club_logos", + verbose_name="logo", + width=200, + ), + ), + migrations.AlterField( + model_name="club", + name="page", + field=models.OneToOneField( + blank=True, + on_delete=django.db.models.deletion.CASCADE, + related_name="club", + to="core.page", + ), + ), + migrations.AlterField( + model_name="club", + name="short_description", + field=models.CharField( + blank=True, + default="", + help_text="A summary of what your club does. This will be displayed on the club list page.", + max_length=1000, + verbose_name="short description", + ), + ), + ] diff --git a/club/models.py b/club/models.py index 4184715a..e7e99cda 100644 --- a/club/models.py +++ b/club/models.py @@ -26,7 +26,6 @@ from __future__ import annotations from typing import Iterable, Self from django.conf import settings -from django.core import validators from django.core.cache import cache from django.core.exceptions import ObjectDoesNotExist, ValidationError from django.core.validators import RegexValidator, validate_email @@ -35,48 +34,43 @@ from django.db.models import Exists, F, OuterRef, Q from django.urls import reverse from django.utils import timezone from django.utils.functional import cached_property +from django.utils.text import slugify from django.utils.timezone import localdate from django.utils.translation import gettext_lazy as _ +from core.fields import ResizedImageField from core.models import Group, Notification, Page, SithFile, User -# Create your models here. - - -# This function prevents generating migration upon settings change -def get_default_owner_group(): - return settings.SITH_GROUP_ROOT_ID - class Club(models.Model): """The Club class, made as a tree to allow nice tidy organization.""" - id = models.AutoField(primary_key=True, db_index=True) - name = models.CharField(_("name"), max_length=64) + name = models.CharField(_("name"), unique=True, max_length=64) parent = models.ForeignKey( "Club", related_name="children", null=True, blank=True, on_delete=models.CASCADE ) - unix_name = models.CharField( - _("unix name"), - max_length=30, - unique=True, - validators=[ - validators.RegexValidator( - r"^[a-z0-9][a-z0-9._-]*[a-z0-9]$", - _( - "Enter a valid unix name. This value may contain only " - "letters, numbers ./-/_ characters." - ), - ) - ], - error_messages={"unique": _("A club with that unix name already exists.")}, + slug_name = models.SlugField( + _("slug name"), max_length=30, unique=True, editable=False ) - logo = models.ImageField( - upload_to="club_logos", verbose_name=_("logo"), null=True, blank=True + logo = ResizedImageField( + upload_to="club_logos", + verbose_name=_("logo"), + null=True, + blank=True, + force_format="WEBP", + height=200, + width=200, ) is_active = models.BooleanField(_("is active"), default=True) short_description = models.CharField( - _("short description"), max_length=1000, default="", blank=True, null=True + _("short description"), + max_length=1000, + default="", + blank=True, + help_text=_( + "A summary of what your club does. " + "This will be displayed on the club list page." + ), ) address = models.CharField(_("address"), max_length=254) home = models.OneToOneField( @@ -88,7 +82,7 @@ class Club(models.Model): on_delete=models.SET_NULL, ) page = models.OneToOneField( - Page, related_name="club", blank=True, null=True, on_delete=models.CASCADE + Page, related_name="club", blank=True, on_delete=models.CASCADE ) members_group = models.OneToOneField( Group, related_name="club", on_delete=models.PROTECT @@ -98,7 +92,7 @@ class Club(models.Model): ) class Meta: - ordering = ["name", "unix_name"] + ordering = ["name"] def __str__(self): return self.name @@ -106,10 +100,12 @@ class Club(models.Model): @transaction.atomic() def save(self, *args, **kwargs): creation = self._state.adding + if (slug := slugify(self.name)[:30]) != self.slug_name: + self.slug_name = slug if not creation: db_club = Club.objects.get(id=self.id) - if self.unix_name != db_club.unix_name: - self.home.name = self.unix_name + if self.name != db_club.name: + self.home.name = self.slug_name self.home.save() if self.name != db_club.name: self.board_group.name = f"{self.name} - Bureau" @@ -123,11 +119,9 @@ class Club(models.Model): self.members_group = Group.objects.create( name=f"{self.name} - Membres", is_manually_manageable=False ) - super().save(*args, **kwargs) - if creation: self.make_home() self.make_page() - cache.set(f"sith_club_{self.unix_name}", self) + super().save(*args, **kwargs) def get_absolute_url(self): return reverse("club:club_view", kwargs={"club_id": self.id}) @@ -155,49 +149,37 @@ class Club(models.Model): def make_home(self) -> None: if self.home: return - home_root = SithFile.objects.filter(parent=None, name="clubs").first() - root = User.objects.filter(username="root").first() - if home_root and root: - home = SithFile(parent=home_root, name=self.unix_name, owner=root) - home.save() - self.home = home - self.save() + home_root = SithFile.objects.get(parent=None, name="clubs") + root = User.objects.get(id=settings.SITH_ROOT_USER_ID) + self.home = SithFile.objects.create( + parent=home_root, name=self.slug_name, owner=root + ) def make_page(self) -> None: - root = User.objects.filter(username="root").first() - if not self.page: - club_root = Page.objects.filter(name=settings.SITH_CLUB_ROOT_PAGE).first() - if root and club_root: - public = Group.objects.filter(id=settings.SITH_GROUP_PUBLIC_ID).first() - p = Page(name=self.unix_name) - p.parent = club_root - p.save(force_lock=True) - if public: - p.view_groups.add(public) - p.save(force_lock=True) - if self.parent and self.parent.page: - p.parent = self.parent.page - self.page = p - self.save() - elif self.page and self.page.name != self.unix_name: - self.page.unset_lock() - self.page.name = self.unix_name - self.page.save(force_lock=True) - elif ( - self.page - and self.parent - and self.parent.page - and self.page.parent != self.parent.page - ): - self.page.unset_lock() + page_name = self.slug_name + if not self.page_id: + # Club.page is a OneToOneField, so if we are inside this condition + # then self._meta.state.adding is True. + club_root = Page.objects.get(name=settings.SITH_CLUB_ROOT_PAGE) + public = Group.objects.get(id=settings.SITH_GROUP_PUBLIC_ID) + p = Page(name=page_name, parent=club_root) + p.save(force_lock=True) + p.view_groups.add(public) + if self.parent and self.parent.page_id: + p.parent_id = self.parent.page_id + self.page = p + return + self.page.unset_lock() + if self.page.name != page_name: + self.page.name = page_name + elif self.parent and self.parent.page and self.page.parent != self.parent.page: self.page.parent = self.parent.page - self.page.save(force_lock=True) + self.page.save(force_lock=True) def delete(self, *args, **kwargs) -> tuple[int, dict[str, int]]: # Invalidate the cache of this club and of its memberships for membership in self.members.ongoing().select_related("user"): cache.delete(f"membership_{self.id}_{membership.user.id}") - cache.delete(f"sith_club_{self.unix_name}") self.board_group.delete() self.members_group.delete() return super().delete(*args, **kwargs) diff --git a/club/templates/club/club_detail.jinja b/club/templates/club/club_detail.jinja index 42e93b81..2d2c5719 100644 --- a/club/templates/club/club_detail.jinja +++ b/club/templates/club/club_detail.jinja @@ -4,7 +4,7 @@ {% block content %}
{% if club.logo %} - + {% endif %} {% if page_revision %} {{ page_revision|markdown }} diff --git a/club/templates/club/club_tools.jinja b/club/templates/club/club_tools.jinja index fa9584fa..db0c22f6 100644 --- a/club/templates/club/club_tools.jinja +++ b/club/templates/club/club_tools.jinja @@ -16,7 +16,7 @@

{% trans %}Counters:{% endtrans %}

{% endif %} - {% if object.unix_name == settings.SITH_LAUNDERETTE_MANAGER['unix_name'] %} + {% if object.id == settings.SITH_LAUNDERETTE_CLUB_ID %}
  • {% trans %}Manage launderettes{% endtrans %}
  • {% endif %}
    diff --git a/club/tests.py b/club/tests.py index a9b7e2e6..be3cc655 100644 --- a/club/tests.py +++ b/club/tests.py @@ -27,7 +27,6 @@ from club.forms import MailingForm from club.models import Club, Mailing, Membership from core.baker_recipes import subscriber_user from core.models import AnonymousUser, User -from sith.settings import SITH_BAR_MANAGER, SITH_MAIN_CLUB_ID class TestClub(TestCase): @@ -64,12 +63,8 @@ class TestClub(TestCase): # not subscribed cls.public = User.objects.get(username="public") - cls.ae = Club.objects.filter(pk=SITH_MAIN_CLUB_ID)[0] - cls.club = Club.objects.create( - name="Fake Club", - unix_name="fake-club", - address="5 rue de la République, 90000 Belfort", - ) + cls.ae = Club.objects.get(pk=settings.SITH_MAIN_CLUB_ID) + cls.club = baker.make(Club) cls.members_url = reverse("club:club_members", kwargs={"club_id": cls.club.id}) a_month_ago = now() - timedelta(days=30) yesterday = now() - timedelta(days=1) @@ -579,13 +574,11 @@ class TestMailingForm(TestCase): cls.krophil = User.objects.get(username="krophil") cls.comunity = User.objects.get(username="comunity") cls.root = User.objects.get(username="root") - cls.bdf = Club.objects.get(unix_name=SITH_BAR_MANAGER["unix_name"]) - cls.mail_url = reverse("club:mailing", kwargs={"club_id": cls.bdf.id}) - - def setUp(self): + cls.club = Club.objects.get(id=settings.SITH_PDF_CLUB_ID) + cls.mail_url = reverse("club:mailing", kwargs={"club_id": cls.club.id}) Membership( - user=self.rbatsbak, - club=self.bdf, + user=cls.rbatsbak, + club=cls.club, start_date=timezone.now(), role=settings.SITH_CLUB_ROLES_ID["Board member"], ).save() @@ -894,13 +887,13 @@ class TestClubSellingView(TestCase): @classmethod def setUpTestData(cls): - cls.ae = Club.objects.get(unix_name="ae") - cls.skia = User.objects.get(username="skia") + cls.club = baker.make(Club) + cls.admin = baker.make(User, is_superuser=True) def test_page_not_internal_error(self): """Test that the page does not return and internal error.""" - self.client.force_login(self.skia) + self.client.force_login(self.admin) response = self.client.get( - reverse("club:club_sellings", kwargs={"club_id": self.ae.id}) + reverse("club:club_sellings", kwargs={"club_id": self.club.id}) ) assert response.status_code == 200 diff --git a/club/views.py b/club/views.py index 6d37ea83..e03df328 100644 --- a/club/views.py +++ b/club/views.py @@ -39,10 +39,16 @@ from django.urls import reverse, reverse_lazy from django.utils import timezone from django.utils.translation import gettext as _t from django.utils.translation import gettext_lazy as _ -from django.views.generic import DetailView, ListView, TemplateView, View +from django.views.generic import DetailView, ListView, View from django.views.generic.edit import CreateView, DeleteView, UpdateView -from club.forms import ClubEditForm, ClubMemberForm, MailingForm, SellingsForm +from club.forms import ( + ClubAdminEditForm, + ClubEditForm, + ClubMemberForm, + MailingForm, + SellingsForm, +) from club.models import Club, Mailing, MailingSubscription, Membership from com.views import ( PosterCreateBaseView, @@ -78,23 +84,23 @@ class ClubTabsMixin(TabedViewMixin): } ] if self.request.user.can_view(self.object): - tab_list.append( - { - "url": reverse( - "club:club_members", kwargs={"club_id": self.object.id} - ), - "slug": "members", - "name": _("Members"), - } - ) - tab_list.append( - { - "url": reverse( - "club:club_old_members", kwargs={"club_id": self.object.id} - ), - "slug": "elderlies", - "name": _("Old members"), - } + tab_list.extend( + [ + { + "url": reverse( + "club:club_members", kwargs={"club_id": self.object.id} + ), + "slug": "members", + "name": _("Members"), + }, + { + "url": reverse( + "club:club_old_members", kwargs={"club_id": self.object.id} + ), + "slug": "elderlies", + "name": _("Old members"), + }, + ] ) if self.object.page: tab_list.append( @@ -134,30 +140,30 @@ class ClubTabsMixin(TabedViewMixin): "name": _("Edit club page"), } ) - tab_list.append( - { - "url": reverse( - "club:club_sellings", kwargs={"club_id": self.object.id} - ), - "slug": "sellings", - "name": _("Sellings"), - } - ) - tab_list.append( - { - "url": reverse("club:mailing", kwargs={"club_id": self.object.id}), - "slug": "mailing", - "name": _("Mailing list"), - } - ) - tab_list.append( - { - "url": reverse( - "club:poster_list", kwargs={"club_id": self.object.id} - ), - "slug": "posters", - "name": _("Posters list"), - } + tab_list.extend( + [ + { + "url": reverse( + "club:club_sellings", kwargs={"club_id": self.object.id} + ), + "slug": "sellings", + "name": _("Sellings"), + }, + { + "url": reverse( + "club:mailing", kwargs={"club_id": self.object.id} + ), + "slug": "mailing", + "name": _("Mailing list"), + }, + { + "url": reverse( + "club:poster_list", kwargs={"club_id": self.object.id} + ), + "slug": "posters", + "name": _("Posters list"), + }, + ] ) if self.request.user.is_owner(self.object): tab_list.append( @@ -189,8 +195,11 @@ class ClubView(ClubTabsMixin, DetailView): def get_context_data(self, **kwargs): kwargs = super().get_context_data(**kwargs) - if self.object.page and self.object.page.revisions.exists(): - kwargs["page_revision"] = self.object.page.revisions.last().content + kwargs["page_revision"] = ( + PageRev.objects.filter(page_id=self.object.page_id) + .order_by("-date") + .first() + ) return kwargs @@ -466,7 +475,7 @@ class ClubEditPropView(ClubTabsMixin, CanEditPropMixin, UpdateView): model = Club pk_url_kwarg = "club_id" - fields = ["name", "unix_name", "parent", "is_active"] + fields = ["name", "parent", "is_active"] template_name = "core/edit.jinja" current_tab = "props" @@ -476,8 +485,8 @@ class ClubCreateView(PermissionRequiredMixin, CreateView): model = Club pk_url_kwarg = "club_id" - fields = ["name", "unix_name", "parent"] - template_name = "core/edit.jinja" + fields = ["name", "parent"] + template_name = "core/create.jinja" permission_required = "club.add_club" @@ -533,26 +542,19 @@ class ClubMailingView(ClubTabsMixin, CanEditMixin, DetailFormView): def get_form_kwargs(self): kwargs = super().get_form_kwargs() - kwargs["club_id"] = self.get_object().id + kwargs["club_id"] = self.object.id kwargs["user_id"] = self.request.user.id - kwargs["mailings"] = self.mailings + kwargs["mailings"] = self.object.mailings.all() return kwargs - def dispatch(self, request, *args, **kwargs): - self.mailings = Mailing.objects.filter(club_id=self.get_object().id).all() - return super().dispatch(request, *args, **kwargs) - def get_context_data(self, **kwargs): kwargs = super().get_context_data(**kwargs) - kwargs["club"] = self.get_object() + mailings = list(self.object.mailings.all()) + kwargs["club"] = self.object kwargs["user"] = self.request.user - kwargs["mailings"] = self.mailings - kwargs["mailings_moderated"] = ( - kwargs["mailings"].exclude(is_moderated=False).all() - ) - kwargs["mailings_not_moderated"] = ( - kwargs["mailings"].exclude(is_moderated=True).all() - ) + kwargs["mailings"] = mailings + kwargs["mailings_moderated"] = [m for m in mailings if m.is_moderated] + kwargs["mailings_not_moderated"] = [m for m in mailings if not m.is_moderated] kwargs["form_actions"] = { "NEW_MALING": self.form_class.ACTION_NEW_MAILING, "NEW_SUBSCRIPTION": self.form_class.ACTION_NEW_SUBSCRIPTION, @@ -563,7 +565,7 @@ class ClubMailingView(ClubTabsMixin, CanEditMixin, DetailFormView): def add_new_mailing(self, cleaned_data) -> ValidationError | None: """Create a new mailing list from the form.""" mailing = Mailing( - club=self.get_object(), + club=self.object, email=cleaned_data["mailing_email"], moderator=self.request.user, is_moderated=False, @@ -640,7 +642,7 @@ class ClubMailingView(ClubTabsMixin, CanEditMixin, DetailFormView): return resp def get_success_url(self, **kwargs): - return reverse_lazy("club:mailing", kwargs={"club_id": self.get_object().id}) + return reverse("club:mailing", kwargs={"club_id": self.object.id}) class MailingDeleteView(CanEditMixin, DeleteView): diff --git a/core/management/commands/populate.py b/core/management/commands/populate.py index 21fde2e5..7e13f28e 100644 --- a/core/management/commands/populate.py +++ b/core/management/commands/populate.py @@ -120,10 +120,7 @@ class Command(BaseCommand): club_root = SithFile.objects.create(name="clubs", owner=root) sas = SithFile.objects.create(name="SAS", owner=root) main_club = Club.objects.create( - id=1, - name=settings.SITH_MAIN_CLUB["name"], - unix_name=settings.SITH_MAIN_CLUB["unix_name"], - address=settings.SITH_MAIN_CLUB["address"], + id=1, name="AE", address="6 Boulevard Anatole France, 90000 Belfort" ) main_club.board_group.permissions.add( *Permission.objects.filter( @@ -131,16 +128,14 @@ class Command(BaseCommand): ) ) bar_club = Club.objects.create( - id=2, - name=settings.SITH_BAR_MANAGER["name"], - unix_name=settings.SITH_BAR_MANAGER["unix_name"], - address=settings.SITH_BAR_MANAGER["address"], + id=settings.SITH_PDF_CLUB_ID, + name="PdF", + address="6 Boulevard Anatole France, 90000 Belfort", ) Club.objects.create( - id=84, - name=settings.SITH_LAUNDERETTE_MANAGER["name"], - unix_name=settings.SITH_LAUNDERETTE_MANAGER["unix_name"], - address=settings.SITH_LAUNDERETTE_MANAGER["address"], + id=settings.SITH_LAUNDERETTE_CLUB_ID, + name="Laverie", + address="6 Boulevard Anatole France, 90000 Belfort", ) self.reset_index("club") @@ -353,31 +348,17 @@ Welcome to the wiki page! # Clubs Club.objects.create( - name="Bibo'UT", - unix_name="bibout", - address="46 de la Boustifaille", - parent=main_club, + name="Bibo'UT", address="46 de la Boustifaille", parent=main_club ) guyut = Club.objects.create( - name="Guy'UT", - unix_name="guyut", - address="42 de la Boustifaille", - parent=main_club, - ) - Club.objects.create( - name="Woenzel'UT", unix_name="woenzel", address="Woenzel", parent=guyut + name="Guy'UT", address="42 de la Boustifaille", parent=main_club ) + Club.objects.create(name="Woenzel'UT", address="Woenzel", parent=guyut) troll = Club.objects.create( - name="Troll Penché", - unix_name="troll", - address="Terre Du Milieu", - parent=main_club, + name="Troll Penché", address="Terre Du Milieu", parent=main_club ) refound = Club.objects.create( - name="Carte AE", - unix_name="carte_ae", - address="Jamais imprimée", - parent=main_club, + name="Carte AE", address="Jamais imprimée", parent=main_club ) Membership.objects.create(user=skia, club=main_club, role=3) diff --git a/core/management/commands/populate_more.py b/core/management/commands/populate_more.py index 7acec959..447b6b98 100644 --- a/core/management/commands/populate_more.py +++ b/core/management/commands/populate_more.py @@ -64,12 +64,12 @@ class Command(BaseCommand): ) ) self.make_club( - Club.objects.get(unix_name="ae"), + Club.objects.get(id=settings.SITH_MAIN_CLUB_ID), random.sample(subscribers_now, k=min(30, len(subscribers_now))), random.sample(old_subscribers, k=min(60, len(old_subscribers))), ) self.make_club( - Club.objects.get(unix_name="troll"), + Club.objects.get(name="Troll Penché"), random.sample(subscribers_now, k=min(20, len(subscribers_now))), random.sample(old_subscribers, k=min(80, len(old_subscribers))), ) @@ -235,7 +235,7 @@ class Command(BaseCommand): categories = list( ProductType.objects.filter(name__in=[c.name for c in categories]) ) - ae = Club.objects.get(unix_name="ae") + ae = Club.objects.get(id=settings.SITH_MAIN_CLUB_ID) other_clubs = random.sample(list(Club.objects.all()), k=3) groups = list( Group.objects.filter(name__in=["Subscribers", "Old subscribers", "Public"]) diff --git a/core/models.py b/core/models.py index 4748f311..1af12405 100644 --- a/core/models.py +++ b/core/models.py @@ -421,13 +421,9 @@ class User(AbstractUser): def is_launderette_manager(self): from club.models import Club - return ( - Club.objects.filter( - unix_name=settings.SITH_LAUNDERETTE_MANAGER["unix_name"] - ) - .first() - .get_membership_for(self) - ) + return Club.objects.get( + id=settings.SITH_LAUNDERETTE_CLUB_ID + ).get_membership_for(self) @cached_property def is_banned_alcohol(self) -> bool: diff --git a/core/templates/core/user_detail.jinja b/core/templates/core/user_detail.jinja index 5fceb126..771ead72 100644 --- a/core/templates/core/user_detail.jinja +++ b/core/templates/core/user_detail.jinja @@ -132,111 +132,104 @@ - {% if - user == profile - or user.memberships.ongoing().exists() - or user.is_board_member - or user.is_in_group(name=settings.SITH_BAR_MANAGER_BOARD_GROUP) - %} - {# if the user is member of a club, he can view the subscription state #} -
    - {% if profile.is_subscribed %} - {% if user == profile or user.is_root or user.is_board_member %} -
    - {{ user_subscription(profile) }} -
    - {% endif %} - {% if user == profile or user.is_root or user.is_board_member or user.is_launderette_manager %} -
    - {# Shows tokens bought by the user #} - {{ show_tokens(profile) }} - {# Shows slots took by the user #} - {{ show_slots(profile) }} -
    - {% endif %} - {% else %} -
    - {% trans %}Not subscribed{% endtrans %} - {% if user.is_board_member %} - - {% trans %}New subscription{% endtrans %} - + {% if user == profile or user.memberships.ongoing().exists() %} + {# if the user is member of a club, he can view the subscription state #} +
    + {% if profile.is_subscribed %} + {% if user == profile or user.is_root or user.is_board_member %} +
    + {{ user_subscription(profile) }} +
    {% endif %} + {% if user == profile or user.is_root or user.is_board_member or user.is_launderette_manager %} +
    + {{ show_tokens(profile) }} + {{ show_slots(profile) }} +
    + {% endif %} + {% else %} +
    + {% trans %}Not subscribed{% endtrans %} + {% if user.is_board_member %} + + {% trans %}New subscription{% endtrans %} + + {% endif %} + {% endif %} +
    {% endif %} -
    -{% endif %} -
    -{% if profile.was_subscribed and (user == profile or user.has_perm("subscription.view_subscription")) %} -
    -
    - - {% trans %}Subscription history{% endtrans %} - - - - -
    -
    - - - - - - - - - - {% for sub in profile.subscriptions.all() %} - - - - - - - {% endfor %} -
    {% trans %}Subscription start{% endtrans %}{% trans %}Subscription end{% endtrans %}{% trans %}Subscription type{% endtrans %}{% trans %}Payment method{% endtrans %}
    {{ sub.subscription_start }}{{ sub.subscription_end }}{{ sub.subscription_type }}{{ sub.get_payment_method_display() }}
    -
    -
    -
    -{% endif %} - -
    - {% if user.is_root or user.is_board_member %} -
    - {% csrf_token %} - {{ gift_form.label }} - {{ gift_form.user }} - -
    - {% if profile.gifts.exists() %} - {% set gifts = profile.gifts.order_by("-date")|list %} -
    +
    + {% if profile.was_subscribed and (user == profile or user.has_perm("subscription.view_subscription")) %}
    - {% trans %}Last given gift :{% endtrans %} {{ gifts[0] }} + {% trans %}Subscription history{% endtrans %}
    -
      - {% for gift in gifts %} -
    • {{ gift }} - - - -
    • + + + + + + + + + + {% for sub in profile.subscriptions.all() %} + + + + + + {% endfor %} - +
      {% trans %}Subscription start{% endtrans %}{% trans %}Subscription end{% endtrans %}{% trans %}Subscription type{% endtrans %}{% trans %}Payment method{% endtrans %}
      {{ sub.subscription_start }}{{ sub.subscription_end }}{{ sub.subscription_type }}{{ sub.get_payment_method_display() }}
    - {% else %} - {% trans %}No gift given yet{% endtrans %} +
    +
    {% endif %} + +
    + {% if user.is_root or user.is_board_member %} +
    + {% csrf_token %} + {{ gift_form.label }} + {{ gift_form.user }} + +
    + {% if profile.gifts.exists() %} + {% set gifts = profile.gifts.order_by("-date")|list %} +
    +
    +
    + + {% trans %}Last given gift :{% endtrans %} {{ gifts[0] }} + + + + +
    +
    +
      + {% for gift in gifts %} +
    • {{ gift }} + + + +
    • + {% endfor %} +
    +
    + {% else %} + {% trans %}No gift given yet{% endtrans %} + {% endif %} +
    + {% endif %}
    - {% endif %} -
    {% endblock %} diff --git a/core/views/user.py b/core/views/user.py index 8e7b092c..cc75f36d 100644 --- a/core/views/user.py +++ b/core/views/user.py @@ -251,17 +251,7 @@ class UserTabsMixin(TabedViewMixin): if ( hasattr(user, "customer") and user.customer - and ( - user == self.request.user - or self.request.user.is_in_group( - pk=settings.SITH_GROUP_ACCOUNTING_ADMIN_ID - ) - or self.request.user.is_in_group( - name=settings.SITH_BAR_MANAGER["unix_name"] - + settings.SITH_BOARD_SUFFIX - ) - or self.request.user.is_root - ) + and (user == self.request.user or user.has_perm("counter.view_customer")) ): tab_list.append( { @@ -370,12 +360,7 @@ class UserStatsView(UserTabsMixin, CanViewMixin, DetailView): raise Http404 if not ( - profile == request.user - or request.user.is_in_group(pk=settings.SITH_GROUP_ACCOUNTING_ADMIN_ID) - or request.user.is_in_group( - name=settings.SITH_BAR_MANAGER["unix_name"] + settings.SITH_BOARD_SUFFIX - ) - or request.user.is_root + profile == request.user or request.user.has_perm("counter.view_customer") ): raise PermissionDenied @@ -599,14 +584,9 @@ class UserAccountBase(UserTabsMixin, DetailView): current_tab = "account" queryset = User.objects.select_related("customer") - def dispatch(self, request, *arg, **kwargs): # Manually validates the rights - if ( - kwargs.get("user_id") == request.user.id - or request.user.is_in_group(pk=settings.SITH_GROUP_ACCOUNTING_ADMIN_ID) - or request.user.is_in_group( - name=settings.SITH_BAR_MANAGER["unix_name"] + settings.SITH_BOARD_SUFFIX - ) - or request.user.is_root + def dispatch(self, request, *arg, **kwargs): + if kwargs.get("user_id") == request.user.id or request.user.has_perm( + "counter.view_customer" ): return super().dispatch(request, *arg, **kwargs) raise PermissionDenied diff --git a/counter/models.py b/counter/models.py index 1467c9f4..efa74fb1 100644 --- a/counter/models.py +++ b/counter/models.py @@ -44,7 +44,6 @@ from core.fields import ResizedImageField from core.models import Group, Notification, User from core.utils import get_start_of_semester from counter.apps import PAYMENT_METHOD -from sith.settings import SITH_MAIN_CLUB from subscription.models import Subscription @@ -519,13 +518,6 @@ class Counter(models.Model): return reverse("eboutic:main") return reverse("counter:details", kwargs={"counter_id": self.id}) - def __getattribute__(self, name: str): - if name == "edit_groups": - return Group.objects.filter( - name=self.club.unix_name + settings.SITH_BOARD_SUFFIX - ).all() - return object.__getattribute__(self, name) - def is_owned_by(self, user: User) -> bool: if user.is_anonymous: return False @@ -569,7 +561,7 @@ class Counter(models.Model): if self.type != "BAR": return False # at least one of the barmen is in the AE board - ae = Club.objects.get(unix_name=SITH_MAIN_CLUB["unix_name"]) + ae = Club.objects.get(id=settings.SITH_MAIN_CLUB_ID) return any(ae.get_membership_for(barman) for barman in self.barmen_list) def get_top_barmen(self) -> QuerySet: diff --git a/counter/tests/test_counter.py b/counter/tests/test_counter.py index d50bb6c4..ab2ab946 100644 --- a/counter/tests/test_counter.py +++ b/counter/tests/test_counter.py @@ -783,7 +783,7 @@ class TestCounterStats(TestCase): s = Selling( label=barbar.name, product=barbar, - club=Club.objects.get(name=settings.SITH_MAIN_CLUB["name"]), + club=baker.make(Club), counter=cls.counter, unit_price=2, seller=cls.skia, diff --git a/galaxy/management/commands/generate_galaxy_test_data.py b/galaxy/management/commands/generate_galaxy_test_data.py index d0dea4a5..ada43a36 100644 --- a/galaxy/management/commands/generate_galaxy_test_data.py +++ b/galaxy/management/commands/generate_galaxy_test_data.py @@ -86,7 +86,7 @@ class Command(BaseCommand): self.logger.info("The Galaxy is being populated by the Sith.") self.logger.info("Cleaning old Galaxy population") - Club.objects.filter(unix_name__startswith="galaxy-").delete() + Club.objects.filter(name__startswith="galaxy-").delete() Group.objects.filter(name__startswith="galaxy-").delete() Page.objects.filter(name__startswith="galaxy-").delete() User.objects.filter(username__startswith="galaxy-").delete() diff --git a/launderette/models.py b/launderette/models.py index 5d6977e2..81357768 100644 --- a/launderette/models.py +++ b/launderette/models.py @@ -47,16 +47,12 @@ class Launderette(models.Model): """Method to see if that object can be edited by the given user.""" if user.is_anonymous: return False - launderette_club = Club.objects.filter( - unix_name=settings.SITH_LAUNDERETTE_MANAGER["unix_name"] - ).first() + launderette_club = Club.objects.get(id=settings.SITH_LAUNDERETTE_CLUB_ID) m = launderette_club.get_membership_for(user) return bool(m and m.role >= 9) def can_be_edited_by(self, user): - launderette_club = Club.objects.filter( - unix_name=settings.SITH_LAUNDERETTE_MANAGER["unix_name"] - ).first() + launderette_club = Club.objects.get(id=settings.SITH_LAUNDERETTE_CLUB_ID) m = launderette_club.get_membership_for(user) return bool(m and m.role >= 2) @@ -105,9 +101,7 @@ class Machine(models.Model): """Method to see if that object can be edited by the given user.""" if user.is_anonymous: return False - launderette_club = Club.objects.filter( - unix_name=settings.SITH_LAUNDERETTE_MANAGER["unix_name"] - ).first() + launderette_club = Club.objects.get(id=settings.SITH_LAUNDERETTE_CLUB_ID) m = launderette_club.get_membership_for(user) return bool(m and m.role >= 9) @@ -154,9 +148,7 @@ class Token(models.Model): """Method to see if that object can be edited by the given user.""" if user.is_anonymous: return False - launderette_club = Club.objects.filter( - unix_name=settings.SITH_LAUNDERETTE_MANAGER["unix_name"] - ).first() + launderette_club = Club.objects.get(id=settings.SITH_LAUNDERETTE_CLUB_ID) m = launderette_club.get_membership_for(user) return bool(m and m.role >= 9) diff --git a/launderette/views.py b/launderette/views.py index 92a81dad..1b0f111b 100644 --- a/launderette/views.py +++ b/launderette/views.py @@ -196,9 +196,7 @@ class LaunderetteCreateView(PermissionRequiredMixin, CreateView): permission_required = "launderette.add_launderette" def form_valid(self, form): - club = Club.objects.filter( - unix_name=settings.SITH_LAUNDERETTE_MANAGER["unix_name"] - ).first() + club = Club.objects.get(id=settings.SITH_LAUNDERETTE_CLUB_ID) c = Counter(name=form.instance.name, club=club, type="OFFICE") c.save() form.instance.counter = c diff --git a/locale/fr/LC_MESSAGES/django.po b/locale/fr/LC_MESSAGES/django.po index 19b164df..79841e95 100644 --- a/locale/fr/LC_MESSAGES/django.po +++ b/locale/fr/LC_MESSAGES/django.po @@ -6,7 +6,7 @@ msgid "" msgstr "" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2025-02-25 16:38+0100\n" +"POT-Creation-Date: 2025-03-01 10:56+0100\n" "PO-Revision-Date: 2016-07-18\n" "Last-Translator: Maréchal \n" @@ -656,11 +656,11 @@ msgid "Linked operation:" msgstr "Opération liée : " #: accounting/templates/accounting/operation_edit.jinja -#: com/templates/com/news_edit.jinja com/templates/com/poster_edit.jinja -#: com/templates/com/screen_edit.jinja com/templates/com/weekmail.jinja -#: core/templates/core/create.jinja core/templates/core/edit.jinja -#: core/templates/core/file_edit.jinja core/templates/core/macros_pages.jinja -#: core/templates/core/page_prop.jinja +#: club/templates/club/edit_club.jinja com/templates/com/news_edit.jinja +#: com/templates/com/poster_edit.jinja com/templates/com/screen_edit.jinja +#: com/templates/com/weekmail.jinja core/templates/core/create.jinja +#: core/templates/core/edit.jinja core/templates/core/file_edit.jinja +#: core/templates/core/macros_pages.jinja core/templates/core/page_prop.jinja #: core/templates/core/user_godfathers.jinja #: core/templates/core/user_godfathers_tree.jinja #: core/templates/core/user_preferences.jinja @@ -882,20 +882,8 @@ msgid "You do not have the permission to do that" msgstr "Vous n'avez pas la permission de faire cela" #: club/models.py -msgid "unix name" -msgstr "nom unix" - -#: club/models.py -msgid "" -"Enter a valid unix name. This value may contain only letters, numbers ./-/_ " -"characters." -msgstr "" -"Entrez un nom UNIX valide. Cette valeur peut contenir uniquement des " -"lettres, des nombres, et les caractères ./-/_" - -#: club/models.py -msgid "A club with that unix name already exists." -msgstr "Un club avec ce nom UNIX existe déjà." +msgid "slug name" +msgstr "nom slug" #: club/models.py msgid "logo" @@ -909,6 +897,14 @@ msgstr "actif" msgid "short description" msgstr "description courte" +#: club/models.py +msgid "" +"A summary of what your club does. This will be displayed on the club list " +"page." +msgstr "" +"Un résumé des activités des activités de votre club. Ceci sera affiché sur " +"la page de la liste des clubs." + #: club/models.py core/models.py msgid "address" msgstr "Adresse" @@ -988,7 +984,7 @@ msgstr "inactif" msgid "New club" msgstr "Nouveau club" -#: club/templates/club/club_list.jinja club/templates/club/stats.jinja +#: club/templates/club/club_list.jinja msgid "There is no club in this website." msgstr "Il n'y a pas de club dans ce site web." @@ -1059,7 +1055,7 @@ msgstr "Suivant" msgid "Sales" msgstr "Ventes" -#: club/templates/club/club_sellings.jinja club/templates/club/stats.jinja +#: club/templates/club/club_sellings.jinja #: counter/templates/counter/cash_summary_list.jinja msgid "Show" msgstr "Montrer" @@ -1160,6 +1156,35 @@ msgstr "Comptabilité : " msgid "Manage launderettes" msgstr "Gestion des laveries" +#: club/templates/club/edit_club.jinja core/templates/core/edit.jinja +#, python-format +msgid "Edit %(name)s" +msgstr "Éditer %(name)s" + +#: club/templates/club/edit_club.jinja +msgid "Club properties" +msgstr "Propriétés du club" + +#: club/templates/club/edit_club.jinja +msgid "" +"The following form fields are linked to the core properties of a club. Only " +"admin users can see and edit them." +msgstr "" +"Les champs de formulaire suivants sont liées aux propriétés essentielles d'un " +"club. Seuls les administrateurs peuvent voir et modifier ceux-ci." + +#: club/templates/club/edit_club.jinja +msgid "Club informations" +msgstr "Informations du club" + +#: club/templates/club/edit_club.jinja +msgid "" +"The following form fields are linked to the basic description of a club. All " +"board members of this club can see and edit them." +msgstr "" +"Les champs de formulaire suivants sont liées à la description basique d'un club. " +"Tous les membres du bureau du club peuvent voir et modifier ceux-ci." + #: club/templates/club/mailing.jinja msgid "Mailing lists" msgstr "Mailing listes" @@ -1218,10 +1243,6 @@ msgstr "Créer une liste de diffusion" msgid "No page existing for this club" msgstr "Aucune page n'existe pour ce club" -#: club/templates/club/stats.jinja -msgid "Club stats" -msgstr "Statistiques du club" - #: club/views.py msgid "Members" msgstr "Membres" @@ -2427,11 +2448,6 @@ msgstr "Confirmation" msgid "Cancel" msgstr "Annuler" -#: core/templates/core/edit.jinja -#, python-format -msgid "Edit %(name)s" -msgstr "Éditer %(name)s" - #: core/templates/core/file.jinja core/templates/core/file_list.jinja msgid "File list" msgstr "Liste de fichiers" @@ -2837,6 +2853,7 @@ msgid "Users" msgstr "Utilisateurs" #: core/templates/core/search.jinja core/views/user.py +#: counter/templates/counter/product_list.jinja msgid "Clubs" msgstr "Clubs" @@ -3182,7 +3199,7 @@ msgid "Bans" msgstr "Bans" #: core/templates/core/user_tools.jinja counter/forms.py -#: counter/views/mixins.py +#: counter/templates/counter/product_list.jinja counter/views/mixins.py msgid "Counters" msgstr "Comptoirs" diff --git a/rootplace/tests/test_merge_users.py b/rootplace/tests/test_merge_users.py index ad66fdd8..f26e16db 100644 --- a/rootplace/tests/test_merge_users.py +++ b/rootplace/tests/test_merge_users.py @@ -18,6 +18,7 @@ from django.conf import settings from django.test import TestCase from django.urls import reverse from django.utils.timezone import localtime, now +from model_bakery import baker from club.models import Club from core.models import Group, User @@ -28,7 +29,7 @@ from subscription.models import Subscription class TestMergeUser(TestCase): @classmethod def setUpTestData(cls): - cls.ae = Club.objects.get(unix_name="ae") + cls.club = baker.make(Club) cls.eboutic = Counter.objects.get(name="Eboutic") cls.barbar = Product.objects.get(code="BARB") cls.barbar.selling_price = 2 @@ -97,7 +98,7 @@ class TestMergeUser(TestCase): Selling( label="barbar", counter=self.eboutic, - club=self.ae, + club=self.club, product=self.barbar, customer=self.to_keep.customer, seller=self.root, @@ -108,7 +109,7 @@ class TestMergeUser(TestCase): Selling( label="barbar", counter=self.eboutic, - club=self.ae, + club=self.club, product=self.barbar, customer=self.to_delete.customer, seller=self.root, @@ -180,7 +181,7 @@ class TestMergeUser(TestCase): Selling( label="barbar", counter=self.eboutic, - club=self.ae, + club=self.club, product=self.barbar, customer=self.to_delete.customer, seller=self.root, @@ -208,7 +209,7 @@ class TestMergeUser(TestCase): Selling( label="barbar", counter=self.eboutic, - club=self.ae, + club=self.club, product=self.barbar, customer=self.to_keep.customer, seller=self.root, diff --git a/sith/settings.py b/sith/settings.py index 8191251f..41a70070 100644 --- a/sith/settings.py +++ b/sith/settings.py @@ -332,27 +332,9 @@ SITH_TWITTER = "@ae_utbm" SITH_ENABLE_GALAXY = False # AE configuration -# TODO: keep only that first setting, with the ID, and do the same for the other clubs SITH_MAIN_CLUB_ID = env.int("SITH_MAIN_CLUB_ID", default=1) -SITH_MAIN_CLUB = { - "name": "AE", - "unix_name": "ae", - "address": "6 Boulevard Anatole France, 90000 Belfort", -} - -# Bar managers -SITH_BAR_MANAGER = { - "name": "Pdf", - "unix_name": "pdfesti", - "address": "6 Boulevard Anatole France, 90000 Belfort", -} - -# Launderette managers -SITH_LAUNDERETTE_MANAGER = { - "name": "Laverie", - "unix_name": "laverie", - "address": "6 Boulevard Anatole France, 90000 Belfort", -} +SITH_PDF_CLUB_ID = env.int("SITH_PDF_CLUB_ID", default=2) +SITH_LAUNDERETTE_CLUB_ID = env.int("SITH_LAUNDERETTE_CLUB_ID", default=84) # Main root for club pages SITH_CLUB_ROOT_PAGE = "clubs" @@ -405,10 +387,6 @@ SITH_SAS_IMAGES_PER_PAGE = 60 SITH_BOARD_SUFFIX = "-bureau" SITH_MEMBER_SUFFIX = "-membres" -SITH_MAIN_BOARD_GROUP = SITH_MAIN_CLUB["unix_name"] + SITH_BOARD_SUFFIX -SITH_MAIN_MEMBERS_GROUP = SITH_MAIN_CLUB["unix_name"] + SITH_MEMBER_SUFFIX -SITH_BAR_MANAGER_BOARD_GROUP = SITH_BAR_MANAGER["unix_name"] + SITH_BOARD_SUFFIX - SITH_PROFILE_DEPARTMENTS = [ ("TC", _("TC")), ("IMSI", _("IMSI")),