mirror of
https://github.com/ae-utbm/sith.git
synced 2026-03-29 14:59:45 +00:00
Compare commits
1 Commits
club-list
...
upgrade_xa
| Author | SHA1 | Date | |
|---|---|---|---|
|
e47b6ba105
|
@@ -6,7 +6,7 @@ from ninja_extra.pagination import PageNumberPaginationExtra
|
|||||||
from ninja_extra.schemas import PaginatedResponseSchema
|
from ninja_extra.schemas import PaginatedResponseSchema
|
||||||
|
|
||||||
from api.auth import ApiKeyAuth
|
from api.auth import ApiKeyAuth
|
||||||
from api.permissions import CanView, HasPerm
|
from api.permissions import CanAccessLookup, CanView, HasPerm
|
||||||
from club.models import Club, Membership
|
from club.models import Club, Membership
|
||||||
from club.schemas import (
|
from club.schemas import (
|
||||||
ClubSchema,
|
ClubSchema,
|
||||||
@@ -22,11 +22,13 @@ class ClubController(ControllerBase):
|
|||||||
@route.get(
|
@route.get(
|
||||||
"/search",
|
"/search",
|
||||||
response=PaginatedResponseSchema[SimpleClubSchema],
|
response=PaginatedResponseSchema[SimpleClubSchema],
|
||||||
|
auth=[ApiKeyAuth(), SessionAuth()],
|
||||||
|
permissions=[CanAccessLookup],
|
||||||
url_name="search_club",
|
url_name="search_club",
|
||||||
)
|
)
|
||||||
@paginate(PageNumberPaginationExtra, page_size=50)
|
@paginate(PageNumberPaginationExtra, page_size=50)
|
||||||
def search_club(self, filters: Query[ClubSearchFilterSchema]):
|
def search_club(self, filters: Query[ClubSearchFilterSchema]):
|
||||||
return filters.filter(Club.objects.order_by("name")).values()
|
return filters.filter(Club.objects.all())
|
||||||
|
|
||||||
@route.get(
|
@route.get(
|
||||||
"/{int:club_id}",
|
"/{int:club_id}",
|
||||||
|
|||||||
@@ -315,22 +315,3 @@ class JoinClubForm(ClubMemberForm):
|
|||||||
_("You are already a member of this club"), code="invalid"
|
_("You are already a member of this club"), code="invalid"
|
||||||
)
|
)
|
||||||
return super().clean()
|
return super().clean()
|
||||||
|
|
||||||
|
|
||||||
class ClubSearchForm(forms.ModelForm):
|
|
||||||
class Meta:
|
|
||||||
model = Club
|
|
||||||
fields = ["name"]
|
|
||||||
widgets = {"name": forms.SearchInput(attrs={"autocomplete": "off"})}
|
|
||||||
|
|
||||||
club_status = forms.NullBooleanField(
|
|
||||||
label=_("Club status"),
|
|
||||||
widget=forms.RadioSelect(
|
|
||||||
choices=[(True, _("Active")), (False, _("Inactive")), ("", _("All clubs"))],
|
|
||||||
),
|
|
||||||
initial=True,
|
|
||||||
)
|
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
|
||||||
super().__init__(*args, **kwargs)
|
|
||||||
self.fields["name"].required = False
|
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ class ClubProfileSchema(ModelSchema):
|
|||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Club
|
model = Club
|
||||||
fields = ["id", "name", "logo", "is_active", "short_description"]
|
fields = ["id", "name", "logo"]
|
||||||
|
|
||||||
url: str
|
url: str
|
||||||
|
|
||||||
|
|||||||
@@ -1,47 +0,0 @@
|
|||||||
#club-list {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
gap: 2em;
|
|
||||||
padding: 2em;
|
|
||||||
|
|
||||||
.card {
|
|
||||||
display: block;
|
|
||||||
background-color: unset;
|
|
||||||
|
|
||||||
.club-image {
|
|
||||||
float: left;
|
|
||||||
margin-right: 2rem;
|
|
||||||
margin-bottom: .5rem;
|
|
||||||
width: 150px;
|
|
||||||
height: 150px;
|
|
||||||
border-radius: 10%;
|
|
||||||
background-color: rgba(173, 173, 173, 0.2);
|
|
||||||
|
|
||||||
@media screen and (max-width: 500px) {
|
|
||||||
width: 100px;
|
|
||||||
height: 100px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
i.club-image {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
justify-content: center;
|
|
||||||
color: black;
|
|
||||||
}
|
|
||||||
|
|
||||||
.content {
|
|
||||||
display: block;
|
|
||||||
text-align: justify;
|
|
||||||
|
|
||||||
h4 {
|
|
||||||
margin-top: 0;
|
|
||||||
margin-right: .5rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
p {
|
|
||||||
font-size: 100%;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,75 +1,52 @@
|
|||||||
{% if is_fragment %}
|
{% extends "core/base.jinja" %}
|
||||||
{% extends "core/base_fragment.jinja" %}
|
|
||||||
|
|
||||||
{# Don't display tabs and errors #}
|
{% block title -%}
|
||||||
{% block tabs %}
|
{% trans %}Club list{% endtrans %}
|
||||||
{% endblock %}
|
{%- endblock %}
|
||||||
{% block errors %}
|
|
||||||
{% endblock %}
|
|
||||||
{% else %}
|
|
||||||
{% extends "core/base.jinja" %}
|
|
||||||
{% block additional_css %}
|
|
||||||
<link rel="stylesheet" href="{{ static("club/list.scss") }}">
|
|
||||||
{% endblock %}
|
|
||||||
{% block description -%}
|
|
||||||
{% trans %}The list of all clubs existing at UTBM.{% endtrans %}
|
|
||||||
{%- endblock %}
|
|
||||||
{% block title -%}
|
|
||||||
{% trans %}Club list{% endtrans %}
|
|
||||||
{%- endblock %}
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
{% from "core/macros.jinja" import paginate_htmx %}
|
{% block description -%}
|
||||||
|
{% trans %}The list of all clubs existing at UTBM.{% endtrans %}
|
||||||
|
{%- endblock %}
|
||||||
|
|
||||||
|
{% macro display_club(club) -%}
|
||||||
|
|
||||||
|
{% if club.is_active or user.is_root %}
|
||||||
|
|
||||||
|
<li><a href="{{ url('club:club_view', club_id=club.id) }}">{{ club.name }}</a>
|
||||||
|
|
||||||
|
{% if not club.is_active %}
|
||||||
|
({% trans %}inactive{% endtrans %})
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% if club.president %} - <a href="{{ url('core:user_profile', user_id=club.president.user.id) }}">{{ club.president.user }}</a>{% endif %}
|
||||||
|
{% if club.short_description %}<p>{{ club.short_description|markdown }}</p>{% endif %}
|
||||||
|
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{%- if club.children.all()|length != 0 %}
|
||||||
|
<ul>
|
||||||
|
{%- for c in club.children.order_by('name').prefetch_related("children") %}
|
||||||
|
{{ display_club(c) }}
|
||||||
|
{%- endfor %}
|
||||||
|
</ul>
|
||||||
|
{%- endif -%}
|
||||||
|
</li>
|
||||||
|
{%- endmacro %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<main>
|
{% if user.is_root %}
|
||||||
<h3>{% trans %}Filters{% endtrans %}</h3>
|
<p><a href="{{ url('club:club_new') }}">{% trans %}New club{% endtrans %}</a></p>
|
||||||
<form
|
{% endif %}
|
||||||
id="club-list-filters"
|
{% if club_list %}
|
||||||
hx-get="{{ url("club:club_list") }}"
|
|
||||||
hx-target="#content"
|
|
||||||
hx-swap="outerHtml"
|
|
||||||
>
|
|
||||||
<div class="row gap-4x">
|
|
||||||
{{ form }}
|
|
||||||
</div>
|
|
||||||
<button type="submit" class="btn btn-blue margin-bottom">
|
|
||||||
<i class="fa fa-magnifying-glass"></i>{% trans %}Search{% endtrans %}
|
|
||||||
</button>
|
|
||||||
</form>
|
|
||||||
<h3>{% trans %}Club list{% endtrans %}</h3>
|
<h3>{% trans %}Club list{% endtrans %}</h3>
|
||||||
{% if user.has_perm("club.add_club") %}
|
<ul>
|
||||||
<br>
|
{%- for club in club_list %}
|
||||||
<a href="{{ url('club:club_new') }}" class="btn btn-blue">
|
{{ display_club(club) }}
|
||||||
<i class="fa fa-plus"></i> {% trans %}New club{% endtrans %}
|
{%- endfor %}
|
||||||
</a>
|
</ul>
|
||||||
{% endif %}
|
{% else %}
|
||||||
<section class="aria-busy-grow" id="club-list">
|
{% trans %}There is no club in this website.{% endtrans %}
|
||||||
{% for club in object_list %}
|
{% endif %}
|
||||||
<div class="card">
|
|
||||||
{% set club_url = club.get_absolute_url() %}
|
|
||||||
<a href="{{ club_url }}">
|
|
||||||
{% if club.logo %}
|
|
||||||
<img class="club-image" src="{{ club.logo.url }}" alt="logo {{ club.name }}">
|
|
||||||
{% else %}
|
|
||||||
<i class="fa-regular fa-image fa-4x club-image"></i>
|
|
||||||
{% endif %}
|
|
||||||
</a>
|
|
||||||
<div class="content">
|
|
||||||
<a href="{{ club_url }}">
|
|
||||||
<h4>
|
|
||||||
{{ club.name }} {% if not club.is_active %}({% trans %}inactive{% endtrans %}){% endif %}
|
|
||||||
</h4>
|
|
||||||
</a>
|
|
||||||
{{ club.short_description|markdown }}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{% endfor %}
|
|
||||||
</section>
|
|
||||||
{% if is_paginated %}
|
|
||||||
{{ paginate_htmx(request, page_obj, paginator) }}
|
|
||||||
{% endif %}
|
|
||||||
</main>
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,15 +1,12 @@
|
|||||||
from datetime import timedelta
|
from datetime import timedelta
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
from django.test import Client
|
|
||||||
from django.urls import reverse
|
|
||||||
from django.utils.timezone import localdate
|
from django.utils.timezone import localdate
|
||||||
from model_bakery import baker
|
from model_bakery import baker
|
||||||
from model_bakery.recipe import Recipe
|
from model_bakery.recipe import Recipe
|
||||||
|
|
||||||
from club.models import Club, Membership
|
from club.models import Club, Membership
|
||||||
from core.baker_recipes import subscriber_user
|
from core.baker_recipes import subscriber_user
|
||||||
from core.models import User
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.django_db
|
@pytest.mark.django_db
|
||||||
@@ -28,14 +25,3 @@ def test_club_queryset_having_board_member():
|
|||||||
|
|
||||||
club_ids = Club.objects.having_board_member(user).values_list("id", flat=True)
|
club_ids = Club.objects.having_board_member(user).values_list("id", flat=True)
|
||||||
assert set(club_ids) == {clubs[1].id, clubs[2].id}
|
assert set(club_ids) == {clubs[1].id, clubs[2].id}
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize("nb_additional_clubs", [10, 30])
|
|
||||||
@pytest.mark.parametrize("is_fragment", [True, False])
|
|
||||||
@pytest.mark.django_db
|
|
||||||
def test_club_list(client: Client, nb_additional_clubs: int, is_fragment):
|
|
||||||
client.force_login(baker.make(User))
|
|
||||||
baker.make(Club, _quantity=nb_additional_clubs)
|
|
||||||
headers = {"HX-Request": True} if is_fragment else {}
|
|
||||||
res = client.get(reverse("club:club_list"), headers=headers)
|
|
||||||
assert res.status_code == 200
|
|
||||||
|
|||||||
@@ -44,19 +44,13 @@ from django.utils.translation import gettext
|
|||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
from django.views.generic import DetailView, ListView, View
|
from django.views.generic import DetailView, ListView, View
|
||||||
from django.views.generic.detail import SingleObjectMixin
|
from django.views.generic.detail import SingleObjectMixin
|
||||||
from django.views.generic.edit import (
|
from django.views.generic.edit import CreateView, DeleteView, UpdateView
|
||||||
CreateView,
|
|
||||||
DeleteView,
|
|
||||||
FormMixin,
|
|
||||||
UpdateView,
|
|
||||||
)
|
|
||||||
|
|
||||||
from club.forms import (
|
from club.forms import (
|
||||||
ClubAddMemberForm,
|
ClubAddMemberForm,
|
||||||
ClubAdminEditForm,
|
ClubAdminEditForm,
|
||||||
ClubEditForm,
|
ClubEditForm,
|
||||||
ClubOldMemberForm,
|
ClubOldMemberForm,
|
||||||
ClubSearchForm,
|
|
||||||
JoinClubForm,
|
JoinClubForm,
|
||||||
MailingForm,
|
MailingForm,
|
||||||
SellingsForm,
|
SellingsForm,
|
||||||
@@ -72,12 +66,7 @@ from com.views import (
|
|||||||
from core.auth.mixins import CanEditMixin, PermissionOrClubBoardRequiredMixin
|
from core.auth.mixins import CanEditMixin, PermissionOrClubBoardRequiredMixin
|
||||||
from core.models import Page, PageRev
|
from core.models import Page, PageRev
|
||||||
from core.views import BasePageEditView, DetailFormView, UseFragmentsMixin
|
from core.views import BasePageEditView, DetailFormView, UseFragmentsMixin
|
||||||
from core.views.mixins import (
|
from core.views.mixins import FragmentMixin, FragmentRenderer, TabedViewMixin
|
||||||
AllowFragment,
|
|
||||||
FragmentMixin,
|
|
||||||
FragmentRenderer,
|
|
||||||
TabedViewMixin,
|
|
||||||
)
|
|
||||||
from counter.models import Selling
|
from counter.models import Selling
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
@@ -191,41 +180,15 @@ class ClubTabsMixin(TabedViewMixin):
|
|||||||
return tab_list
|
return tab_list
|
||||||
|
|
||||||
|
|
||||||
class ClubListView(AllowFragment, FormMixin, ListView):
|
class ClubListView(ListView):
|
||||||
"""List the clubs of the AE, with a form to perform basic search.
|
"""List the Clubs."""
|
||||||
|
|
||||||
Notes:
|
|
||||||
This view is fully public, because we want to advertise as much as possible
|
|
||||||
the cultural life of the AE.
|
|
||||||
In accordance with that matter, searching and listing the clubs is done
|
|
||||||
entirely server-side (no AlpineJS involved) ;
|
|
||||||
this is done this way in order to be sure the page is the most accessible
|
|
||||||
and SEO-friendly possible, even if it makes the UX slightly less smooth.
|
|
||||||
"""
|
|
||||||
|
|
||||||
|
model = Club
|
||||||
template_name = "club/club_list.jinja"
|
template_name = "club/club_list.jinja"
|
||||||
form_class = ClubSearchForm
|
queryset = (
|
||||||
queryset = Club.objects.order_by("name")
|
Club.objects.filter(parent=None).order_by("name").prefetch_related("children")
|
||||||
paginate_by = 1
|
)
|
||||||
|
context_object_name = "club_list"
|
||||||
def get_form_kwargs(self):
|
|
||||||
res = super().get_form_kwargs()
|
|
||||||
if self.request.GET:
|
|
||||||
res |= {"data": self.request.GET, "initial": self.request.GET}
|
|
||||||
return res
|
|
||||||
|
|
||||||
def get_queryset(self):
|
|
||||||
form: ClubSearchForm = self.get_form()
|
|
||||||
qs = self.queryset
|
|
||||||
if not form.is_bound:
|
|
||||||
return qs.filter(is_active=True)
|
|
||||||
if not form.is_valid():
|
|
||||||
return qs.none()
|
|
||||||
if name := form.cleaned_data.get("name"):
|
|
||||||
qs = qs.filter(name__icontains=name)
|
|
||||||
if (is_active := form.cleaned_data.get("club_status")) is not None:
|
|
||||||
qs = qs.filter(is_active=is_active)
|
|
||||||
return qs
|
|
||||||
|
|
||||||
|
|
||||||
class ClubView(ClubTabsMixin, DetailView):
|
class ClubView(ClubTabsMixin, DetailView):
|
||||||
|
|||||||
@@ -39,12 +39,16 @@ class Command(BaseCommand):
|
|||||||
return None
|
return None
|
||||||
return xapian.version_string()
|
return xapian.version_string()
|
||||||
|
|
||||||
def _desired_version(self) -> str:
|
def _desired_version(self) -> tuple[str, str, str]:
|
||||||
with open(
|
with open(
|
||||||
Path(__file__).parent.parent.parent.parent / "pyproject.toml", "rb"
|
Path(__file__).parent.parent.parent.parent / "pyproject.toml", "rb"
|
||||||
) as f:
|
) as f:
|
||||||
pyproject = tomli.load(f)
|
pyproject = tomli.load(f)
|
||||||
return pyproject["tool"]["xapian"]["version"]
|
return (
|
||||||
|
pyproject["tool"]["xapian"]["version"],
|
||||||
|
pyproject["tool"]["xapian"]["core-sha256"],
|
||||||
|
pyproject["tool"]["xapian"]["bindings-sha256"],
|
||||||
|
)
|
||||||
|
|
||||||
def handle(self, *args, force: bool, **options):
|
def handle(self, *args, force: bool, **options):
|
||||||
if not os.environ.get("VIRTUAL_ENV", None):
|
if not os.environ.get("VIRTUAL_ENV", None):
|
||||||
@@ -53,7 +57,7 @@ class Command(BaseCommand):
|
|||||||
)
|
)
|
||||||
return
|
return
|
||||||
|
|
||||||
desired = self._desired_version()
|
desired, core_checksum, bindings_checksum = self._desired_version()
|
||||||
if desired == self._current_version():
|
if desired == self._current_version():
|
||||||
if not force:
|
if not force:
|
||||||
self.stdout.write(
|
self.stdout.write(
|
||||||
@@ -65,7 +69,12 @@ class Command(BaseCommand):
|
|||||||
f"Installing xapian version {desired} at {os.environ['VIRTUAL_ENV']}"
|
f"Installing xapian version {desired} at {os.environ['VIRTUAL_ENV']}"
|
||||||
)
|
)
|
||||||
subprocess.run(
|
subprocess.run(
|
||||||
[str(Path(__file__).parent / "install_xapian.sh"), desired],
|
[
|
||||||
|
str(Path(__file__).parent / "install_xapian.sh"),
|
||||||
|
desired,
|
||||||
|
core_checksum,
|
||||||
|
bindings_checksum,
|
||||||
|
],
|
||||||
env=dict(os.environ),
|
env=dict(os.environ),
|
||||||
check=True,
|
check=True,
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,7 +1,11 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
# Originates from https://gist.github.com/jorgecarleitao/ab6246c86c936b9c55fd
|
# Originates from https://gist.github.com/jorgecarleitao/ab6246c86c936b9c55fd
|
||||||
# first argument of the script is Xapian version (e.g. 1.2.19)
|
# first argument of the script is Xapian version (e.g. 1.2.19)
|
||||||
|
# second argument of the script is core sha256
|
||||||
|
# second argument of the script is binding sha256
|
||||||
VERSION="$1"
|
VERSION="$1"
|
||||||
|
CORE_SHA256="$2"
|
||||||
|
BINDINGS_SHA256="$3"
|
||||||
|
|
||||||
# Cleanup env vars for auto discovery mechanism
|
# Cleanup env vars for auto discovery mechanism
|
||||||
unset CPATH
|
unset CPATH
|
||||||
@@ -21,9 +25,15 @@ BINDINGS=xapian-bindings-$VERSION
|
|||||||
|
|
||||||
# download
|
# download
|
||||||
echo "Downloading source..."
|
echo "Downloading source..."
|
||||||
curl -O "https://oligarchy.co.uk/xapian/$VERSION/${CORE}.tar.xz"
|
curl -O "https://oligarchy.co.uk/xapian/$VERSION/${CORE}.tar.xz" || exit 1
|
||||||
|
|
||||||
|
echo "${CORE_SHA256} ${CORE}.tar.xz" | sha256sum -c - || exit 1
|
||||||
|
|
||||||
curl -O "https://oligarchy.co.uk/xapian/$VERSION/${BINDINGS}.tar.xz"
|
curl -O "https://oligarchy.co.uk/xapian/$VERSION/${BINDINGS}.tar.xz"
|
||||||
|
|
||||||
|
echo "${BINDINGS_SHA256} ${BINDINGS}.tar.xz" | sha256sum -c - || exit 1
|
||||||
|
|
||||||
|
|
||||||
# extract
|
# extract
|
||||||
echo "Extracting source..."
|
echo "Extracting source..."
|
||||||
tar xf "${CORE}.tar.xz"
|
tar xf "${CORE}.tar.xz"
|
||||||
|
|||||||
@@ -5,8 +5,9 @@
|
|||||||
<details name="navbar" class="menu">
|
<details name="navbar" class="menu">
|
||||||
<summary class="head">{% trans %}Associations & Clubs{% endtrans %}</summary>
|
<summary class="head">{% trans %}Associations & Clubs{% endtrans %}</summary>
|
||||||
<ul class="content">
|
<ul class="content">
|
||||||
<li><a href="{{ url("core:page", page_name="ae") }}">{% trans %}AE{% endtrans %}</a></li>
|
<li><a href="{{ url('core:page', page_name='ae') }}">{% trans %}AE{% endtrans %}</a></li>
|
||||||
<li><a href="{{ url("club:club_list") }}">{% trans %}AE's clubs{% endtrans %}</a></li>
|
<li><a href="{{ url('core:page', page_name='clubs') }}">{% trans %}AE's clubs{% endtrans %}</a></li>
|
||||||
|
<li><a href="{{ url('core:page', page_name='utbm-associations') }}">{% trans %}Others UTBM's Associations{% endtrans %}</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</details>
|
</details>
|
||||||
<details name="navbar" class="menu">
|
<details name="navbar" class="menu">
|
||||||
|
|||||||
@@ -310,36 +310,16 @@ msgid "The list of all clubs existing at UTBM."
|
|||||||
msgstr "La liste de tous les clubs existants à l'UTBM"
|
msgstr "La liste de tous les clubs existants à l'UTBM"
|
||||||
|
|
||||||
#: club/templates/club/club_list.jinja
|
#: club/templates/club/club_list.jinja
|
||||||
msgid "Filters"
|
msgid "inactive"
|
||||||
msgstr "Filtres"
|
msgstr "inactif"
|
||||||
|
|
||||||
#: club/templates/club/club_list.jinja
|
|
||||||
msgid "Name"
|
|
||||||
msgstr "Nom"
|
|
||||||
|
|
||||||
#: club/templates/club/club_list.jinja
|
|
||||||
msgid "Club state"
|
|
||||||
msgstr "Etat du club"
|
|
||||||
|
|
||||||
#: club/templates/club/club_list.jinja
|
|
||||||
msgid "Active"
|
|
||||||
msgstr "Actif"
|
|
||||||
|
|
||||||
#: club/templates/club/club_list.jinja
|
|
||||||
msgid "Inactive"
|
|
||||||
msgstr "Inactif"
|
|
||||||
|
|
||||||
#: club/templates/club/club_list.jinja
|
|
||||||
msgid "All clubs"
|
|
||||||
msgstr "Tous les clubs"
|
|
||||||
|
|
||||||
#: club/templates/club/club_list.jinja core/templates/core/user_tools.jinja
|
#: club/templates/club/club_list.jinja core/templates/core/user_tools.jinja
|
||||||
msgid "New club"
|
msgid "New club"
|
||||||
msgstr "Nouveau club"
|
msgstr "Nouveau club"
|
||||||
|
|
||||||
#: club/templates/club/club_list.jinja
|
#: club/templates/club/club_list.jinja
|
||||||
msgid "inactive"
|
msgid "There is no club in this website."
|
||||||
msgstr "inactif"
|
msgstr "Il n'y a pas de club dans ce site web."
|
||||||
|
|
||||||
#: club/templates/club/club_members.jinja
|
#: club/templates/club/club_members.jinja
|
||||||
msgid "Club members"
|
msgid "Club members"
|
||||||
@@ -1901,6 +1881,10 @@ msgstr "L'AE"
|
|||||||
msgid "AE's clubs"
|
msgid "AE's clubs"
|
||||||
msgstr "Les clubs de L'AE"
|
msgstr "Les clubs de L'AE"
|
||||||
|
|
||||||
|
#: core/templates/core/base/navbar.jinja
|
||||||
|
msgid "Others UTBM's Associations"
|
||||||
|
msgstr "Les autres associations de l'UTBM"
|
||||||
|
|
||||||
#: core/templates/core/base/navbar.jinja
|
#: core/templates/core/base/navbar.jinja
|
||||||
msgid "Big event"
|
msgid "Big event"
|
||||||
msgstr "Grandes Activités"
|
msgstr "Grandes Activités"
|
||||||
|
|||||||
185
pyproject.toml
185
pyproject.toml
@@ -4,54 +4,54 @@ version = "3"
|
|||||||
description = "Le web Sith de l'AE"
|
description = "Le web Sith de l'AE"
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
authors = [
|
authors = [
|
||||||
{ name = "Skia", email = "skia@hya.sk" },
|
{ name = "Skia", email = "skia@hya.sk" },
|
||||||
{ name = "klmp200", email = "antoine@bartuccio.fr" },
|
{ name = "klmp200", email = "antoine@bartuccio.fr" },
|
||||||
{ name = "Krophil", email = "pierre.brunet@krophil.fr" },
|
{ name = "Krophil", email = "pierre.brunet@krophil.fr" },
|
||||||
{ name = "Maréchal", email = "thgirod@hotmail.com" },
|
{ name = "Maréchal", email = "thgirod@hotmail.com" },
|
||||||
{ name = "Och", email = "francescowitz68@gmail.com" },
|
{ name = "Och", email = "francescowitz68@gmail.com" },
|
||||||
{ name = "tleb", email = "tleb@openmailbox.org" },
|
{ name = "tleb", email = "tleb@openmailbox.org" },
|
||||||
{ name = "Soldat", email = "ryan-68@live.fr" },
|
{ name = "Soldat", email = "ryan-68@live.fr" },
|
||||||
{ name = "Nabos", email = "gnikwo@hotmail.com" },
|
{ name = "Nabos", email = "gnikwo@hotmail.com" },
|
||||||
{ name = "Terre", email = "jbaptiste.lenglet+git@gmail.com" },
|
{ name = "Terre", email = "jbaptiste.lenglet+git@gmail.com" },
|
||||||
{ name = "Lo-J", email = "renaudg779@gmail.com" },
|
{ name = "Lo-J", email = "renaudg779@gmail.com" },
|
||||||
{ name = "Vial", email = "robin.trioux@utbm.fr" },
|
{ name = "Vial", email = "robin.trioux@utbm.fr" },
|
||||||
]
|
]
|
||||||
license = { text = "GPL-3.0-only" }
|
license = { text = "GPL-3.0-only" }
|
||||||
requires-python = "<4.0,>=3.12"
|
requires-python = "<4.0,>=3.12"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"django>=5.2.12,<6.0.0",
|
"django>=5.2.12,<6.0.0",
|
||||||
"django-ninja>=1.5.3,<6.0.0",
|
"django-ninja>=1.5.3,<6.0.0",
|
||||||
"django-ninja-extra>=0.31.0",
|
"django-ninja-extra>=0.31.0",
|
||||||
"Pillow>=12.1.1,<13.0.0",
|
"Pillow>=12.1.1,<13.0.0",
|
||||||
"mistune>=3.2.0,<4.0.0",
|
"mistune>=3.2.0,<4.0.0",
|
||||||
"django-jinja<3.0.0,>=2.11.0",
|
"django-jinja<3.0.0,>=2.11.0",
|
||||||
"cryptography>=46.0.5,<47.0.0",
|
"cryptography>=46.0.5,<47.0.0",
|
||||||
"django-phonenumber-field>=8.4.0,<9.0.0",
|
"django-phonenumber-field>=8.4.0,<9.0.0",
|
||||||
"phonenumbers>=9.0.25,<10.0.0",
|
"phonenumbers>=9.0.25,<10.0.0",
|
||||||
"reportlab>=4.4.10,<5.0.0",
|
"reportlab>=4.4.10,<5.0.0",
|
||||||
"django-haystack<4.0.0,>=3.3.0",
|
"django-haystack<4.0.0,>=3.3.0",
|
||||||
"xapian-haystack<4.0.0,>=3.1.0",
|
"xapian-haystack<4.0.0,>=3.1.0",
|
||||||
"libsass<1.0.0,>=0.23.0",
|
"libsass<1.0.0,>=0.23.0",
|
||||||
"django-ordered-model<4.0.0,>=3.7.4",
|
"django-ordered-model<4.0.0,>=3.7.4",
|
||||||
"django-simple-captcha<1.0.0,>=0.6.3",
|
"django-simple-captcha<1.0.0,>=0.6.3",
|
||||||
"python-dateutil<3.0.0.0,>=2.9.0.post0",
|
"python-dateutil<3.0.0.0,>=2.9.0.post0",
|
||||||
"sentry-sdk>=2.54.0,<3.0.0",
|
"sentry-sdk>=2.54.0,<3.0.0",
|
||||||
"jinja2<4.0.0,>=3.1.6",
|
"jinja2<4.0.0,>=3.1.6",
|
||||||
"django-countries>=8.2.0,<9.0.0",
|
"django-countries>=8.2.0,<9.0.0",
|
||||||
"dict2xml>=1.7.8,<2.0.0",
|
"dict2xml>=1.7.8,<2.0.0",
|
||||||
"Sphinx<6,>=5",
|
"Sphinx<6,>=5",
|
||||||
"tomli>=2.4.0,<3.0.0",
|
"tomli>=2.4.0,<3.0.0",
|
||||||
"django-honeypot>=1.3.0,<2",
|
"django-honeypot>=1.3.0,<2",
|
||||||
"pydantic-extra-types>=2.11.0,<3.0.0",
|
"pydantic-extra-types>=2.11.0,<3.0.0",
|
||||||
"ical>=11.1.0,<12",
|
"ical>=11.1.0,<12",
|
||||||
"redis[hiredis]>=5.3.0,<8.0.0",
|
"redis[hiredis]>=5.3.0,<8.0.0",
|
||||||
"environs[django]>=14.5.0,<15.0.0",
|
"environs[django]>=14.5.0,<15.0.0",
|
||||||
"requests>=2.32.5,<3.0.0",
|
"requests>=2.32.5,<3.0.0",
|
||||||
"honcho>=2.0.0",
|
"honcho>=2.0.0",
|
||||||
"psutil>=7.2.2,<8.0.0",
|
"psutil>=7.2.2,<8.0.0",
|
||||||
"celery[redis]>=5.6.2,<7",
|
"celery[redis]>=5.6.2,<7",
|
||||||
"django-celery-results>=2.5.1",
|
"django-celery-results>=2.5.1",
|
||||||
"django-celery-beat>=2.9.0",
|
"django-celery-beat>=2.9.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[project.urls]
|
[project.urls]
|
||||||
@@ -59,73 +59,74 @@ homepage = "https://ae.utbm.fr/"
|
|||||||
documentation = "https://sith-ae.readthedocs.io/"
|
documentation = "https://sith-ae.readthedocs.io/"
|
||||||
|
|
||||||
[dependency-groups]
|
[dependency-groups]
|
||||||
prod = [
|
prod = ["psycopg[c]>=3.3.3,<4.0.0"]
|
||||||
"psycopg[c]>=3.3.3,<4.0.0",
|
|
||||||
]
|
|
||||||
dev = [
|
dev = [
|
||||||
"django-debug-toolbar>=6.2.0,<7",
|
"django-debug-toolbar>=6.2.0,<7",
|
||||||
"ipython>=9.11.0,<10.0.0",
|
"ipython>=9.11.0,<10.0.0",
|
||||||
"pre-commit>=4.5.1,<5.0.0",
|
"pre-commit>=4.5.1,<5.0.0",
|
||||||
"ruff>=0.15.5,<1.0.0",
|
"ruff>=0.15.5,<1.0.0",
|
||||||
"djhtml>=3.0.10,<4.0.0",
|
"djhtml>=3.0.10,<4.0.0",
|
||||||
"faker>=40.8.0,<41.0.0",
|
"faker>=40.8.0,<41.0.0",
|
||||||
"rjsmin>=1.2.5,<2.0.0",
|
"rjsmin>=1.2.5,<2.0.0",
|
||||||
]
|
]
|
||||||
tests = [
|
tests = [
|
||||||
"freezegun>=1.5.5,<2.0.0",
|
"freezegun>=1.5.5,<2.0.0",
|
||||||
"pytest>=9.0.2,<10.0.0",
|
"pytest>=9.0.2,<10.0.0",
|
||||||
"pytest-cov>=7.0.0,<8.0.0",
|
"pytest-cov>=7.0.0,<8.0.0",
|
||||||
"pytest-django<5.0.0,>=4.12.0",
|
"pytest-django<5.0.0,>=4.12.0",
|
||||||
"model-bakery<2.0.0,>=1.23.3",
|
"model-bakery<2.0.0,>=1.23.3",
|
||||||
"beautifulsoup4>=4.14.3,<5",
|
"beautifulsoup4>=4.14.3,<5",
|
||||||
"lxml>=6.0.2,<7",
|
"lxml>=6.0.2,<7",
|
||||||
]
|
]
|
||||||
docs = [
|
docs = [
|
||||||
"mkdocs<2.0.0,>=1.6.1",
|
"mkdocs<2.0.0,>=1.6.1",
|
||||||
"mkdocs-material>=9.7.5,<10.0.0",
|
"mkdocs-material>=9.7.5,<10.0.0",
|
||||||
"mkdocstrings>=1.0.3,<2.0.0",
|
"mkdocstrings>=1.0.3,<2.0.0",
|
||||||
"mkdocstrings-python>=2.0.3,<3.0.0",
|
"mkdocstrings-python>=2.0.3,<3.0.0",
|
||||||
"mkdocs-include-markdown-plugin>=7.2.1,<8.0.0",
|
"mkdocs-include-markdown-plugin>=7.2.1,<8.0.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[tool.uv]
|
[tool.uv]
|
||||||
default-groups = ["dev", "tests", "docs"]
|
default-groups = ["dev", "tests", "docs"]
|
||||||
|
|
||||||
[tool.xapian]
|
[tool.xapian]
|
||||||
version = "1.4.29"
|
version = "1.4.31"
|
||||||
|
core-sha256 = "fecf609ea2efdc8a64be369715aac733336a11f7480a6545244964ae6bc80811"
|
||||||
|
bindings-sha256 = "a38cc7ba4188cc0bd27dc7369f03906772047087a1c54f1b93355d5e9103c304"
|
||||||
|
|
||||||
|
|
||||||
[tool.ruff]
|
[tool.ruff]
|
||||||
output-format = "concise" # makes ruff error logs easier to read
|
output-format = "concise" # makes ruff error logs easier to read
|
||||||
|
|
||||||
[tool.ruff.lint]
|
[tool.ruff.lint]
|
||||||
select = [
|
select = [
|
||||||
"A", # shadowing of Python builtins
|
"A", # shadowing of Python builtins
|
||||||
"B",
|
"B",
|
||||||
"C4", # use comprehensions when possible
|
"C4", # use comprehensions when possible
|
||||||
"DJ", # django-specific rules,
|
"DJ", # django-specific rules,
|
||||||
"E", # pycodestyle (https://docs.astral.sh/ruff/rules/#pycodestyle-e-w)
|
"E", # pycodestyle (https://docs.astral.sh/ruff/rules/#pycodestyle-e-w)
|
||||||
"ERA", # commented code
|
"ERA", # commented code
|
||||||
"F", # pyflakes (https://docs.astral.sh/ruff/rules/#pyflakes-f)
|
"F", # pyflakes (https://docs.astral.sh/ruff/rules/#pyflakes-f)
|
||||||
"FBT", # boolean trap
|
"FBT", # boolean trap
|
||||||
"FLY", # f-string instead of str.join
|
"FLY", # f-string instead of str.join
|
||||||
"FURB", # https://docs.astral.sh/ruff/rules/#refurb-furb
|
"FURB", # https://docs.astral.sh/ruff/rules/#refurb-furb
|
||||||
"I", # isort
|
"I", # isort
|
||||||
"INT", # gettext
|
"INT", # gettext
|
||||||
"PERF", # performance
|
"PERF", # performance
|
||||||
"PLW", # pylint warnings (https://docs.astral.sh/ruff/rules/#pylint-pl)
|
"PLW", # pylint warnings (https://docs.astral.sh/ruff/rules/#pylint-pl)
|
||||||
"RUF", # Ruff specific rules
|
"RUF", # Ruff specific rules
|
||||||
"SIM", # simplify (https://docs.astral.sh/ruff/rules/#flake8-simplify-sim)
|
"SIM", # simplify (https://docs.astral.sh/ruff/rules/#flake8-simplify-sim)
|
||||||
"T100", # breakpoint()
|
"T100", # breakpoint()
|
||||||
"T2", # print statements
|
"T2", # print statements
|
||||||
"TCH", # type-checking block
|
"TCH", # type-checking block
|
||||||
"UP008", # Use super() instead of super(__class__, self)
|
"UP008", # Use super() instead of super(__class__, self)
|
||||||
"UP009", # utf-8 encoding declaration is unnecessary
|
"UP009", # utf-8 encoding declaration is unnecessary
|
||||||
]
|
]
|
||||||
|
|
||||||
ignore = [
|
ignore = [
|
||||||
"DJ001", # null=True in CharField/TextField. this one would require a migration
|
"DJ001", # null=True in CharField/TextField. this one would require a migration
|
||||||
"E501", # line too long. The rule is too harsh, and the formatter deals with it in most cases
|
"E501", # line too long. The rule is too harsh, and the formatter deals with it in most cases
|
||||||
"RUF012" # mutable class attributes. This rule doesn't integrate well with django
|
"RUF012", # mutable class attributes. This rule doesn't integrate well with django
|
||||||
]
|
]
|
||||||
|
|
||||||
[tool.ruff.lint.pydocstyle]
|
[tool.ruff.lint.pydocstyle]
|
||||||
@@ -141,4 +142,4 @@ sith = "sith.pytest"
|
|||||||
[tool.pytest.ini_options]
|
[tool.pytest.ini_options]
|
||||||
DJANGO_SETTINGS_MODULE = "sith.settings"
|
DJANGO_SETTINGS_MODULE = "sith.settings"
|
||||||
python_files = ["tests.py", "test_*.py", "*_tests.py"]
|
python_files = ["tests.py", "test_*.py", "*_tests.py"]
|
||||||
markers = ["slow"]
|
markers = ["slow"]
|
||||||
|
|||||||
Reference in New Issue
Block a user