diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index bc2bcea5..9943ab73 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -4,19 +4,27 @@ stages: test: stage: test script: + - env - apt-get update - apt-get install -y gettext python3-xapian libgraphviz-dev - pushd /usr/lib/python3/dist-packages/xapian && ln -s _xapian* _xapian.so && popd - export PYTHONPATH="/usr/lib/python3/dist-packages:$PYTHONPATH" - python -c 'import xapian' # Fail immediately if there is a problem with xapian - - pip install -r requirements.txt - - pip install coverage + - pip install -U -r requirements.txt + - pip install -U coverage + - mkdir -p /dev/shm/search_indexes + - ln -s /dev/shm/search_indexes sith/search_indexes - ./manage.py compilemessages - coverage run ./manage.py test - coverage html - coverage report - cd doc - make html # Make documentation + variables: + PIP_CACHE_DIR: "$CI_PROJECT_DIR/.cache/pip_tests" + cache: + paths: + - .cache/pip_tests artifacts: paths: - coverage_report/ @@ -24,5 +32,10 @@ test: black: stage: test script: - - pip install black + - pip install -U black - black --check . + variables: + PIP_CACHE_DIR: "$CI_PROJECT_DIR/.cache/pip_black" + cache: + paths: + - .cache/pip_black diff --git a/.mailmap b/.mailmap new file mode 100644 index 00000000..30fe2218 --- /dev/null +++ b/.mailmap @@ -0,0 +1,18 @@ +Code +Cyl +Juste +Krophil +Lo-J +Nabos +Och +Partoo +Skia +Skia +Sli +Soldat +Terre +Vial +Zar +root +tleb +tleb diff --git a/accounting/tests.py b/accounting/tests.py index f424d8e8..f1d7e855 100644 --- a/accounting/tests.py +++ b/accounting/tests.py @@ -25,7 +25,7 @@ from django.test import TestCase from django.urls import reverse from django.core.management import call_command -from datetime import date +from datetime import date, timedelta from core.models import User from accounting.models import ( @@ -110,6 +110,9 @@ class JournalTest(TestCase): class OperationTest(TestCase): def setUp(self): call_command("populate") + self.tomorrow_formatted = (date.today() + timedelta(days=1)).strftime( + "%d/%m/%Y" + ) self.journal = GeneralJournal.objects.filter(id=1).first() self.skia = User.objects.filter(username="skia").first() at = AccountingType( @@ -158,7 +161,7 @@ class OperationTest(TestCase): "target_type": "OTHER", "target_id": "", "target_label": "Le fantome de la nuit", - "date": "04/12/2020", + "date": self.tomorrow_formatted, "mode": "CASH", "cheque_number": "", "invoice": "", @@ -191,7 +194,7 @@ class OperationTest(TestCase): "target_type": "OTHER", "target_id": "", "target_label": "Le fantome de la nuit", - "date": "04/12/2020", + "date": self.tomorrow_formatted, "mode": "CASH", "cheque_number": "", "invoice": "", @@ -218,7 +221,7 @@ class OperationTest(TestCase): "target_type": "OTHER", "target_id": "", "target_label": "Le fantome du jour", - "date": "04/12/2020", + "date": self.tomorrow_formatted, "mode": "CASH", "cheque_number": "", "invoice": "", @@ -245,7 +248,7 @@ class OperationTest(TestCase): "target_type": "OTHER", "target_id": "", "target_label": "Le fantome de l'aurore", - "date": "04/12/2020", + "date": self.tomorrow_formatted, "mode": "CASH", "cheque_number": "", "invoice": "", diff --git a/accounting/views.py b/accounting/views.py index 693884cf..9f891a09 100644 --- a/accounting/views.py +++ b/accounting/views.py @@ -496,7 +496,7 @@ class OperationCreateView(CanCreateMixin, CreateView): return ret def get_context_data(self, **kwargs): - """ Add journal to the context """ + """Add journal to the context""" kwargs = super(OperationCreateView, self).get_context_data(**kwargs) if self.journal: kwargs["object"] = self.journal @@ -514,7 +514,7 @@ class OperationEditView(CanEditMixin, UpdateView): template_name = "accounting/operation_edit.jinja" def get_context_data(self, **kwargs): - """ Add journal to the context """ + """Add journal to the context""" kwargs = super(OperationEditView, self).get_context_data(**kwargs) kwargs["object"] = self.object.journal return kwargs @@ -735,7 +735,7 @@ class JournalNatureStatementView(JournalTabsMixin, CanViewMixin, DetailView): return statement def get_context_data(self, **kwargs): - """ Add infos to the context """ + """Add infos to the context""" kwargs = super(JournalNatureStatementView, self).get_context_data(**kwargs) kwargs["statement"] = self.big_statement() return kwargs @@ -774,7 +774,7 @@ class JournalPersonStatementView(JournalTabsMixin, CanViewMixin, DetailView): return sum(self.statement(movement_type).values()) def get_context_data(self, **kwargs): - """ Add journal to the context """ + """Add journal to the context""" kwargs = super(JournalPersonStatementView, self).get_context_data(**kwargs) kwargs["credit_statement"] = self.statement("CREDIT") kwargs["debit_statement"] = self.statement("DEBIT") @@ -804,7 +804,7 @@ class JournalAccountingStatementView(JournalTabsMixin, CanViewMixin, DetailView) return statement def get_context_data(self, **kwargs): - """ Add journal to the context """ + """Add journal to the context""" kwargs = super(JournalAccountingStatementView, self).get_context_data(**kwargs) kwargs["statement"] = self.statement() return kwargs diff --git a/api/views/__init__.py b/api/views/__init__.py index 21aacd98..6a3fa8e9 100644 --- a/api/views/__init__.py +++ b/api/views/__init__.py @@ -33,8 +33,8 @@ from core.views import can_view, can_edit def check_if(obj, user, test): """ - Detect if it's a single object or a queryset - aply a given test on individual object and return global permission + Detect if it's a single object or a queryset + aply a given test on individual object and return global permission """ if isinstance(obj, QuerySet): for o in obj: @@ -49,7 +49,7 @@ class ManageModelMixin: @action(detail=True) def id(self, request, pk=None): """ - Get by id (api/v1/router/{pk}/id/) + Get by id (api/v1/router/{pk}/id/) """ self.queryset = get_object_or_404(self.queryset.filter(id=pk)) serializer = self.get_serializer(self.queryset) diff --git a/api/views/api.py b/api/views/api.py index 82d9942b..94dcf35c 100644 --- a/api/views/api.py +++ b/api/views/api.py @@ -33,7 +33,7 @@ from core.templatetags.renderer import markdown @renderer_classes((StaticHTMLRenderer,)) def RenderMarkdown(request): """ - Render Markdown + Render Markdown """ try: data = markdown(request.POST["text"]) diff --git a/api/views/club.py b/api/views/club.py index 38ce16be..d379d0b4 100644 --- a/api/views/club.py +++ b/api/views/club.py @@ -43,7 +43,7 @@ class ClubSerializer(serializers.ModelSerializer): class ClubViewSet(RightModelViewSet): """ - Manage Clubs (api/v1/club/) + Manage Clubs (api/v1/club/) """ serializer_class = ClubSerializer diff --git a/api/views/counter.py b/api/views/counter.py index 5b241031..a57093c3 100644 --- a/api/views/counter.py +++ b/api/views/counter.py @@ -45,7 +45,7 @@ class CounterSerializer(serializers.ModelSerializer): class CounterViewSet(RightModelViewSet): """ - Manage Counters (api/v1/counter/) + Manage Counters (api/v1/counter/) """ serializer_class = CounterSerializer @@ -54,7 +54,7 @@ class CounterViewSet(RightModelViewSet): @action(detail=False) def bar(self, request): """ - Return all bars (api/v1/counter/bar/) + Return all bars (api/v1/counter/bar/) """ self.queryset = self.queryset.filter(type="BAR") serializer = self.get_serializer(self.queryset, many=True) diff --git a/api/views/group.py b/api/views/group.py index 5e6436af..f4bb9951 100644 --- a/api/views/group.py +++ b/api/views/group.py @@ -36,7 +36,7 @@ class GroupSerializer(serializers.ModelSerializer): class GroupViewSet(RightModelViewSet): """ - Manage Groups (api/v1/group/) + Manage Groups (api/v1/group/) """ serializer_class = GroupSerializer diff --git a/api/views/launderette.py b/api/views/launderette.py index cdcacd0a..96c831ef 100644 --- a/api/views/launderette.py +++ b/api/views/launderette.py @@ -72,7 +72,7 @@ class LaunderetteTokenSerializer(serializers.ModelSerializer): class LaunderettePlaceViewSet(RightModelViewSet): """ - Manage Launderette (api/v1/launderette/place/) + Manage Launderette (api/v1/launderette/place/) """ serializer_class = LaunderettePlaceSerializer @@ -81,7 +81,7 @@ class LaunderettePlaceViewSet(RightModelViewSet): class LaunderetteMachineViewSet(RightModelViewSet): """ - Manage Washing Machines (api/v1/launderette/machine/) + Manage Washing Machines (api/v1/launderette/machine/) """ serializer_class = LaunderetteMachineSerializer @@ -90,7 +90,7 @@ class LaunderetteMachineViewSet(RightModelViewSet): class LaunderetteTokenViewSet(RightModelViewSet): """ - Manage Launderette's tokens (api/v1/launderette/token/) + Manage Launderette's tokens (api/v1/launderette/token/) """ serializer_class = LaunderetteTokenSerializer @@ -99,7 +99,7 @@ class LaunderetteTokenViewSet(RightModelViewSet): @action(detail=False) def washing(self, request): """ - Return all washing tokens (api/v1/launderette/token/washing) + Return all washing tokens (api/v1/launderette/token/washing) """ self.queryset = self.queryset.filter(type="WASHING") serializer = self.get_serializer(self.queryset, many=True) @@ -108,7 +108,7 @@ class LaunderetteTokenViewSet(RightModelViewSet): @action(detail=False) def drying(self, request): """ - Return all drying tokens (api/v1/launderette/token/drying) + Return all drying tokens (api/v1/launderette/token/drying) """ self.queryset = self.queryset.filter(type="DRYING") serializer = self.get_serializer(self.queryset, many=True) @@ -117,7 +117,7 @@ class LaunderetteTokenViewSet(RightModelViewSet): @action(detail=False) def avaliable(self, request): """ - Return all avaliable tokens (api/v1/launderette/token/avaliable) + Return all avaliable tokens (api/v1/launderette/token/avaliable) """ self.queryset = self.queryset.filter( borrow_date__isnull=True, user__isnull=True @@ -128,7 +128,7 @@ class LaunderetteTokenViewSet(RightModelViewSet): @action(detail=False) def unavaliable(self, request): """ - Return all unavaliable tokens (api/v1/launderette/token/unavaliable) + Return all unavaliable tokens (api/v1/launderette/token/unavaliable) """ self.queryset = self.queryset.filter( borrow_date__isnull=False, user__isnull=False diff --git a/api/views/user.py b/api/views/user.py index bb45a8a2..be3d97f8 100644 --- a/api/views/user.py +++ b/api/views/user.py @@ -50,8 +50,8 @@ class UserSerializer(serializers.ModelSerializer): class UserViewSet(RightModelViewSet): """ - Manage Users (api/v1/user/) - Only show active users + Manage Users (api/v1/user/) + Only show active users """ serializer_class = UserSerializer @@ -60,7 +60,7 @@ class UserViewSet(RightModelViewSet): @action(detail=False) def birthday(self, request): """ - Return all users born today (api/v1/user/birstdays) + Return all users born today (api/v1/user/birstdays) """ date = datetime.datetime.today() self.queryset = self.queryset.filter(date_of_birth=date) diff --git a/api/views/uv.py b/api/views/uv.py index d1099475..e9790e0b 100644 --- a/api/views/uv.py +++ b/api/views/uv.py @@ -29,10 +29,10 @@ def uv_endpoint(request): def find_uv(lang, year, code): """ - Uses the UTBM API to find an UV. - short_uv is the UV entry in the UV list. It is returned as it contains - information which are not in full_uv. - full_uv is the detailed representation of an UV. + Uses the UTBM API to find an UV. + short_uv is the UV entry in the UV list. It is returned as it contains + information which are not in full_uv. + full_uv is the detailed representation of an UV. """ # query the UV list uvs_url = settings.SITH_PEDAGOGY_UTBM_API + "/uvs/{}/{}".format(lang, year) @@ -57,7 +57,7 @@ def find_uv(lang, year, code): def make_clean_uv(short_uv, full_uv): """ - Cleans the data up so that it corresponds to our data representation. + Cleans the data up so that it corresponds to our data representation. """ res = {} diff --git a/club/forms.py b/club/forms.py index 3f450f78..658b343f 100644 --- a/club/forms.py +++ b/club/forms.py @@ -34,6 +34,7 @@ from club.models import Mailing, MailingSubscription, Club, Membership from core.models import User from core.views.forms import SelectDate, SelectDateTime from counter.models import Counter +from core.views.forms import TzAwareDateTimeField class ClubEditForm(forms.ModelForm): @@ -158,18 +159,9 @@ class MailingForm(forms.Form): class SellingsForm(forms.Form): - begin_date = forms.DateTimeField( - input_formats=["%Y-%m-%d %H:%M:%S"], - label=_("Begin date"), - required=False, - widget=SelectDateTime, - ) - end_date = forms.DateTimeField( - input_formats=["%Y-%m-%d %H:%M:%S"], - label=_("End date"), - required=False, - widget=SelectDateTime, - ) + begin_date = TzAwareDateTimeField(label=_("Begin date"), required=False) + end_date = TzAwareDateTimeField(label=_("End date"), required=False) + counters = forms.ModelMultipleChoiceField( Counter.objects.order_by("name").all(), label=_("Counter"), required=False ) @@ -252,8 +244,8 @@ class ClubMemberForm(forms.Form): def clean_users(self): """ - Check that the user is not trying to add an user already in the club - Also check that the user is valid and has a valid subscription + Check that the user is not trying to add an user already in the club + Also check that the user is valid and has a valid subscription """ cleaned_data = super(ClubMemberForm, self).clean() users = [] @@ -276,7 +268,7 @@ class ClubMemberForm(forms.Form): def clean(self): """ - Check user rights for adding an user + Check user rights for adding an user """ cleaned_data = super(ClubMemberForm, self).clean() diff --git a/club/views.py b/club/views.py index 73c06dd8..574e7b47 100644 --- a/club/views.py +++ b/club/views.py @@ -290,7 +290,7 @@ class ClubMembersView(ClubTabsMixin, CanViewMixin, DetailFormView): def form_valid(self, form): """ - Check user rights + Check user rights """ resp = super(ClubMembersView, self).form_valid(form) diff --git a/com/templates/com/news_list.jinja b/com/templates/com/news_list.jinja index 7c2ec629..dfc664e6 100644 --- a/com/templates/com/news_list.jinja +++ b/com/templates/com/news_list.jinja @@ -6,152 +6,150 @@ {% endblock %} {% block content %} +{% if user.is_in_group(settings.SITH_GROUP_COM_ADMIN_ID) %} + +{% endif %} +
- {% if user.is_in_group(settings.SITH_GROUP_COM_ADMIN_ID) %} - - {% endif %} - -
-
-
{% trans %}Agenda{% endtrans %}
-
- {% for d in NewsDate.objects.filter(end_date__gte=timezone.now(), - news__is_moderated=True, news__type__in=["WEEKLY", - "EVENT"]).order_by('start_date', 'end_date') %} -
-
- {{ d.start_date|localtime|date('D d M Y') }} -
-
- {{ d.start_date|localtime|time(DATETIME_FORMAT) }} - - {{ d.end_date|localtime|time(DATETIME_FORMAT) }} -
- -
{{ d.news.summary|markdown }}
-
- {% endfor %} -
-
- -
-
{% trans %}Birthdays{% endtrans %}
-
- {% if user.is_subscribed %} - {# Cache request for 1 hour #} - {% cache 3600 birthdays %} -
    - {% for d in birthdays.dates('date_of_birth', 'year', 'DESC') %} -
  • - {% trans age=timezone.now().year - d.year %}{{ age }} year old{% endtrans %} - -
  • - {% endfor %} -
- {% endcache %} - {% else %} -

{% trans %}You need an up to date subscription to access this content{% endtrans %}

- {% endif %} -
-
-
- -
- {% for news in object_list.filter(type="NOTICE") %} -
-

{{ news.title }}

-
{{ news.summary|markdown }}
-
- {% endfor %} + {% for news in object_list.filter(type="NOTICE") %} +
+

{{ news.title }}

+
{{ news.summary|markdown }}
+
+ {% endfor %} - {% for news in object_list.filter(dates__start_date__lte=timezone.now(), - dates__end_date__gte=timezone.now(), type="CALL") %} -
-

{{ news.title }}

-
- {{ news.dates.first().start_date|localtime|date(DATETIME_FORMAT) }} - {{ news.dates.first().start_date|localtime|time(DATETIME_FORMAT) }} - - {{ news.dates.first().end_date|localtime|date(DATETIME_FORMAT) }} - {{ news.dates.first().end_date|localtime|time(DATETIME_FORMAT) }} -
-
{{ news.summary|markdown }}
-
- {% endfor %} + {% for news in object_list.filter(dates__start_date__lte=timezone.now(), dates__end_date__gte=timezone.now(), type="CALL") %} +
+

{{ news.title }}

+
+ {{ news.dates.first().start_date|localtime|date(DATETIME_FORMAT) }} + {{ news.dates.first().start_date|localtime|time(DATETIME_FORMAT) }} - + {{ news.dates.first().end_date|localtime|date(DATETIME_FORMAT) }} + {{ news.dates.first().end_date|localtime|time(DATETIME_FORMAT) }} +
+
{{ news.summary|markdown }}
+
+ {% endfor %} - {% set events_dates = NewsDate.objects.filter(end_date__gte=timezone.now(), start_date__lte=timezone.now()+timedelta(days=5), - news__type="EVENT", news__is_moderated=True).datetimes('start_date', 'day') %} -

{% trans %}Events today and the next few days{% endtrans %}

- {% if events_dates %} - {% for d in events_dates %} -
-
-
-
{{ d|localtime|date('D') }}
-
{{ d|localtime|date('d') }}
-
{{ d|localtime|date('b') }}
-
-
-
- {% for news in object_list.filter(dates__start_date__gte=d, - dates__start_date__lte=d+timedelta(days=1), - type="EVENT").exclude(dates__end_date__lt=timezone.now()) - .order_by('dates__start_date') %} -
- -

{{ news.title }}

- -
- {{ news.dates.first().start_date|localtime|time(DATETIME_FORMAT) }} - - {{ news.dates.first().end_date|localtime|time(DATETIME_FORMAT) }} -
-
{{ news.summary|markdown }} -
- {{ fb_quick(news) }} - {{ tweet_quick(news) }} -
-
-
- {% endfor %} -
-
- {% endfor %} - {% else %} -
- {% trans %}Nothing to come...{% endtrans %} -
- {% endif %} + {% set events_dates = NewsDate.objects.filter(end_date__gte=timezone.now(), start_date__lte=timezone.now()+timedelta(days=5), news__type="EVENT", news__is_moderated=True).datetimes('start_date', 'day') %} +

{% trans %}Events today and the next few days{% endtrans %}

+ {% if events_dates %} + {% for d in events_dates %} +
+
+
+
{{ d|localtime|date('D') }}
+
{{ d|localtime|date('d') }}
+
{{ d|localtime|date('b') }}
+
+
+
+ {% for news in object_list.filter(dates__start_date__gte=d, + dates__start_date__lte=d+timedelta(days=1), + type="EVENT").exclude(dates__end_date__lt=timezone.now()) + .order_by('dates__start_date') %} +
+ +

{{ news.title }}

+ +
+ {{ news.dates.first().start_date|localtime|time(DATETIME_FORMAT) }} - + {{ news.dates.first().end_date|localtime|time(DATETIME_FORMAT) }} +
+
{{ news.summary|markdown }} +
+ {{ fb_quick(news) }} + {{ tweet_quick(news) }} +
+
+
+ {% endfor %} +
+
+ {% endfor %} + {% else %} +
+ {% trans %}Nothing to come...{% endtrans %} +
+ {% endif %} - {% set coming_soon = object_list.filter(dates__start_date__gte=timezone.now()+timedelta(days=5), - type="EVENT").order_by('dates__start_date') %} - {% if coming_soon %} -

{% trans %}Coming soon... don't miss!{% endtrans %}

- {% for news in coming_soon %} -
- {{ news.title }} - {{ news.dates.first().start_date|localtime|date(DATETIME_FORMAT) }} - {{ news.dates.first().start_date|localtime|time(DATETIME_FORMAT) }} - - {{ news.dates.first().end_date|localtime|date(DATETIME_FORMAT) }} - {{ news.dates.first().end_date|localtime|time(DATETIME_FORMAT) }} -
- {% endfor %} - {% endif %} + {% set coming_soon = object_list.filter(dates__start_date__gte=timezone.now()+timedelta(days=5), + type="EVENT").order_by('dates__start_date') %} + {% if coming_soon %} +

{% trans %}Coming soon... don't miss!{% endtrans %}

+ {% for news in coming_soon %} +
+ {{ news.title }} + {{ news.dates.first().start_date|localtime|date(DATETIME_FORMAT) }} + {{ news.dates.first().start_date|localtime|time(DATETIME_FORMAT) }} - + {{ news.dates.first().end_date|localtime|date(DATETIME_FORMAT) }} + {{ news.dates.first().end_date|localtime|time(DATETIME_FORMAT) }} +
+ {% endfor %} + {% endif %}
+ +
+
+
{% trans %}Agenda{% endtrans %}
+
+ {% for d in NewsDate.objects.filter(end_date__gte=timezone.now(), + news__is_moderated=True, news__type__in=["WEEKLY", + "EVENT"]).order_by('start_date', 'end_date') %} +
+
+ {{ d.start_date|localtime|date('D d M Y') }} +
+
+ {{ d.start_date|localtime|time(DATETIME_FORMAT) }} - + {{ d.end_date|localtime|time(DATETIME_FORMAT) }} +
+ +
{{ d.news.summary|markdown }}
+
+ {% endfor %} +
+
+ +
+
{% trans %}Birthdays{% endtrans %}
+
+ {% if user.is_subscribed %} + {# Cache request for 1 hour #} + {% cache 3600 "birthdays" %} +
    + {% for d in birthdays.dates('date_of_birth', 'year', 'DESC') %} +
  • + {% trans age=timezone.now().year - d.year %}{{ age }} year old{% endtrans %} + +
  • + {% endfor %} +
+ {% endcache %} + {% else %} +

{% trans %}You need an up to date subscription to access this content{% endtrans %}

+ {% endif %} +
+
+
+
{% endblock %} diff --git a/com/templates/com/poster_list.jinja b/com/templates/com/poster_list.jinja index 7bd340fd..f752013e 100644 --- a/com/templates/com/poster_list.jinja +++ b/com/templates/com/poster_list.jinja @@ -36,8 +36,8 @@
{{ poster.name }}
-
{{ poster.date_begin | date("d/M/Y H:m") }}
-
{{ poster.date_end | date("d/M/Y H:m") }}
+
{{ poster.date_begin | localtime | date("d/M/Y H:m") }}
+
{{ poster.date_end | localtime | date("d/M/Y H:m") }}
{% if app == "com" %} {% trans %}Edit{% endtrans %} diff --git a/com/templates/com/weekmail_preview.jinja b/com/templates/com/weekmail_preview.jinja index 0f160419..44c4da0a 100644 --- a/com/templates/com/weekmail_preview.jinja +++ b/com/templates/com/weekmail_preview.jinja @@ -7,15 +7,33 @@ {% block content %} {% trans %}Back{% endtrans %} -{% if request.GET['send'] %} -

{% trans %}Are you sure you want to send this weekmail?{% endtrans %}

-{% if request.LANGUAGE_CODE != settings.LANGUAGE_CODE[:2] %} -

{% trans %}Warning: you are sending the weekmail in another language than the default one!{% endtrans %}

-{% endif %} -
- {% csrf_token %} - -
+{% if bad_recipients %} +

+ + {% trans %}The following recipients were refused by the SMTP:{% endtrans %} + +

    + {% for r in bad_recipients.keys() %} +
  • {{ r }}
  • + {% endfor %} +
+

+ +
+ {% csrf_token %} + +
+{% else %} + {% if request.GET['send'] %} +

{% trans %}Are you sure you want to send this weekmail?{% endtrans %}

+ {% if request.LANGUAGE_CODE != settings.LANGUAGE_CODE[:2] %} +

{% trans %}Warning: you are sending the weekmail in another language than the default one!{% endtrans %}

+ {% endif %} +
+ {% csrf_token %} + +
+ {% endif %} {% endif %}
{{ weekmail_rendered|safe }} diff --git a/com/tests.py b/com/tests.py index 398b22fe..d42a056e 100644 --- a/com/tests.py +++ b/com/tests.py @@ -79,9 +79,11 @@ class ComTest(TestCase): ) r = self.client.get(reverse("core:index")) self.assertTrue(r.status_code == 200) - self.assertTrue( - """
\\n

ALERTE!

\\n

Caaaataaaapuuuulte!!!!

""" - in str(r.content) + self.assertContains( + r, + """
+

ALERTE!

+

Caaaataaaapuuuulte!!!!

""", ) def test_info_msg(self): @@ -95,9 +97,10 @@ class ComTest(TestCase): ) r = self.client.get(reverse("core:index")) self.assertTrue(r.status_code == 200) - self.assertTrue( - """
\\n

INFO: Caaaataaaapuuuulte!!!!

""" - in str(r.content) + self.assertContains( + r, + """
+

INFO: Caaaataaaapuuuulte!!!!

""", ) def test_birthday_non_subscribed_user(self): diff --git a/com/views.py b/com/views.py index 27d15008..02ddb50d 100644 --- a/com/views.py +++ b/com/views.py @@ -39,6 +39,7 @@ from django.core.exceptions import PermissionDenied from django import forms from datetime import timedelta +from smtplib import SMTPRecipientsRefused from com.models import Sith, News, NewsDate, Weekmail, WeekmailArticle, Screen, Poster from core.views import ( @@ -52,6 +53,7 @@ from core.views import ( from core.views.forms import SelectDateTime, MarkdownInput from core.models import Notification, RealGroup, User from club.models import Club, Mailing +from core.views.forms import TzAwareDateTimeField # Sith object @@ -72,20 +74,14 @@ class PosterForm(forms.ModelForm): "display_time", ] widgets = {"screens": forms.CheckboxSelectMultiple} + help_texts = {"file": _("Format: 16:9 | Resolution: 1920x1080")} - date_begin = forms.DateTimeField( - input_formats=["%Y-%m-%d %H:%M:%S"], + date_begin = TzAwareDateTimeField( label=_("Start date"), - widget=SelectDateTime, required=True, initial=timezone.now().strftime("%Y-%m-%d %H:%M:%S"), ) - date_end = forms.DateTimeField( - input_formats=["%Y-%m-%d %H:%M:%S"], - label=_("End date"), - widget=SelectDateTime, - required=False, - ) + date_end = TzAwareDateTimeField(label=_("End date"), required=False) def __init__(self, *args, **kwargs): self.user = kwargs.pop("user", None) @@ -199,24 +195,10 @@ class NewsForm(forms.ModelForm): "content": MarkdownInput, } - start_date = forms.DateTimeField( - input_formats=["%Y-%m-%d %H:%M:%S"], - label=_("Start date"), - widget=SelectDateTime, - required=False, - ) - end_date = forms.DateTimeField( - input_formats=["%Y-%m-%d %H:%M:%S"], - label=_("End date"), - widget=SelectDateTime, - required=False, - ) - until = forms.DateTimeField( - input_formats=["%Y-%m-%d %H:%M:%S"], - label=_("Until"), - widget=SelectDateTime, - required=False, - ) + start_date = TzAwareDateTimeField(label=_("Start date"), required=False) + end_date = TzAwareDateTimeField(label=_("End date"), required=False) + until = TzAwareDateTimeField(label=_("Until"), required=False) + automoderation = forms.BooleanField(label=_("Automoderation"), required=False) def clean(self): @@ -433,22 +415,35 @@ class NewsDetailView(CanViewMixin, DetailView): # Weekmail -class WeekmailPreviewView(ComTabsMixin, CanEditPropMixin, DetailView): +class WeekmailPreviewView(ComTabsMixin, QuickNotifMixin, CanEditPropMixin, DetailView): model = Weekmail template_name = "com/weekmail_preview.jinja" success_url = reverse_lazy("com:weekmail") current_tab = "weekmail" + def dispatch(self, request, *args, **kwargs): + self.bad_recipients = [] + return super(WeekmailPreviewView, self).dispatch(request, *args, **kwargs) + def post(self, request, *args, **kwargs): self.object = self.get_object() - try: - if request.POST["send"] == "validate": + if request.POST["send"] == "validate": + try: self.object.send() return HttpResponseRedirect( reverse("com:weekmail") + "?qn_weekmail_send_success" ) - except: - pass + except SMTPRecipientsRefused as e: + self.bad_recipients = e.recipients + elif request.POST["send"] == "clean": + try: + self.object.send() # This should fail + except SMTPRecipientsRefused as e: + users = User.objects.filter(email__in=e.recipients.keys()) + for u in users: + u.preferences.receive_weekmail = False + u.preferences.save() + self.quick_notif_list += ["qn_success"] return super(WeekmailPreviewView, self).get(request, *args, **kwargs) def get_object(self, queryset=None): @@ -458,6 +453,7 @@ class WeekmailPreviewView(ComTabsMixin, CanEditPropMixin, DetailView): """Add rendered weekmail""" kwargs = super(WeekmailPreviewView, self).get_context_data(**kwargs) kwargs["weekmail_rendered"] = self.object.render_html() + kwargs["bad_recipients"] = self.bad_recipients return kwargs @@ -534,7 +530,7 @@ class WeekmailEditView(ComTabsMixin, QuickNotifMixin, CanEditPropMixin, UpdateVi return super(WeekmailEditView, self).get(request, *args, **kwargs) def get_context_data(self, **kwargs): - """Add orphan articles """ + """Add orphan articles""" kwargs = super(WeekmailEditView, self).get_context_data(**kwargs) kwargs["orphans"] = WeekmailArticle.objects.filter(weekmail=None) return kwargs diff --git a/core/management/commands/check_front.py b/core/management/commands/check_front.py new file mode 100644 index 00000000..181de23c --- /dev/null +++ b/core/management/commands/check_front.py @@ -0,0 +1,107 @@ +import re +from subprocess import PIPE, Popen, TimeoutExpired + +from django.conf import settings +from django.core.management.base import BaseCommand + +# see https://semver.org/#is-there-a-suggested-regular-expression-regex-to-check-a-semver-string +# added "v?" +semver_regex = re.compile( + """^v?(?P0|[1-9]\d*)\.(?P0|[1-9]\d*)\.(?P0|[1-9]\d*)(?:-(?P(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+(?P[0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$""" +) + + +class Command(BaseCommand): + help = "Checks the front dependencies are up to date." + + def handle(self, *args, **options): + deps = settings.SITH_FRONT_DEP_VERSIONS + + processes = dict( + (url, create_process(url)) + for url in deps.keys() + if parse_semver(deps[url]) is not None + ) + + for url, process in processes.items(): + try: + stdout, stderr = process.communicate(timeout=15) + except TimeoutExpired: + process.kill() + self.stderr.write(self.style.WARNING("{}: timeout".format(url))) + continue + # error, notice, warning + + stdout = stdout.decode("utf-8") + stderr = stderr.decode("utf-8") + + if stderr != "": + self.stderr.write(self.style.WARNING(stderr.strip())) + continue + + # get all tags, parse them as semvers and find the biggest + tags = list_tags(stdout) + tags = map(parse_semver, tags) + tags = filter(lambda tag: tag is not None, tags) + latest_version = max(tags) + + # cannot fail as those which fail are filtered in the processes dict creation + current_version = parse_semver(deps[url]) + assert current_version is not None + + if latest_version == current_version: + msg = "{}: {}".format(url, semver_to_s(current_version)) + self.stdout.write(self.style.SUCCESS(msg)) + else: + msg = "{}: {} < {}".format( + url, semver_to_s(current_version), semver_to_s(latest_version) + ) + self.stdout.write(self.style.ERROR(msg)) + + +def create_process(url): + """Spawn a "git ls-remote --tags" child process.""" + return Popen(["git", "ls-remote", "--tags", url], stdout=PIPE, stderr=PIPE) + + +def list_tags(s): + """Parses "git ls-remote --tags" output. Takes a string.""" + tag_prefix = "refs/tags/" + + for line in s.strip().split("\n"): + # an example line could be: + # "1f41e2293f9c3c1962d2d97afa666207b98a222a\trefs/tags/foo" + parts = line.split("\t") + + # check we have a commit ID (SHA-1 hash) and a tag name + assert len(parts) == 2 + assert len(parts[0]) == 40 + assert parts[1].startswith(tag_prefix) + + # avoid duplicates (a peeled tag will appear twice: as "name" and as "name^{}") + if not parts[1].endswith("^{}"): + yield parts[1][len(tag_prefix) :] + + +def parse_semver(s): + """ + Turns a semver string into a 3-tuple or None if the parsing failed, it is a + prerelease or it has build metadata. + + See https://semver.org + """ + m = semver_regex.match(s) + + if ( + m is None + or m.group("prerelease") is not None + or m.group("buildmetadata") is not None + ): + return None + + return (int(m.group("major")), int(m.group("minor")), int(m.group("patch"))) + + +def semver_to_s(t): + """Expects a 3-tuple with ints and turns it into a string of type "1.2.3".""" + return "{}.{}.{}".format(t[0], t[1], t[2]) diff --git a/core/management/commands/compilestatic.py b/core/management/commands/compilestatic.py index fd956333..51d99f6d 100644 --- a/core/management/commands/compilestatic.py +++ b/core/management/commands/compilestatic.py @@ -31,7 +31,7 @@ from django.conf import settings class Command(BaseCommand): """ - Compiles scss in static folder for production + Compiles scss in static folder for production """ help = "Compile scss files from static folder" diff --git a/core/models.py b/core/models.py index b9f0f243..22bfc1d1 100644 --- a/core/models.py +++ b/core/models.py @@ -1492,7 +1492,9 @@ class OperationLog(models.Model): User, related_name="logs", on_delete=models.SET_NULL, null=True ) operation_type = models.CharField( - _("operation type"), max_length=40, choices=settings.SITH_LOG_OPERATION_TYPE, + _("operation type"), + max_length=40, + choices=settings.SITH_LOG_OPERATION_TYPE, ) def is_owned_by(self, user): diff --git a/core/operations.py b/core/operations.py index 3c6eae9b..29740292 100644 --- a/core/operations.py +++ b/core/operations.py @@ -33,16 +33,16 @@ from django.db import connection, migrations class PsqlRunOnly(migrations.RunSQL): """ - This is an SQL runner that will launch the given command only if - the used DBMS is PostgreSQL. - It may be useful to run Postgres' specific SQL, or to take actions - that would be non-senses with backends other than Postgre, such - as disabling particular constraints that would prevent the migration - to run successfully. + This is an SQL runner that will launch the given command only if + the used DBMS is PostgreSQL. + It may be useful to run Postgres' specific SQL, or to take actions + that would be non-senses with backends other than Postgre, such + as disabling particular constraints that would prevent the migration + to run successfully. - See `club/migrations/0010_auto_20170912_2028.py` as an example. - Some explanations can be found here too: - https://stackoverflow.com/questions/28429933/django-migrations-using-runpython-to-commit-changes + See `club/migrations/0010_auto_20170912_2028.py` as an example. + Some explanations can be found here too: + https://stackoverflow.com/questions/28429933/django-migrations-using-runpython-to-commit-changes """ def _run_sql(self, schema_editor, sqls): diff --git a/core/scss/processor.py b/core/scss/processor.py index 39f099f9..8a5c3334 100644 --- a/core/scss/processor.py +++ b/core/scss/processor.py @@ -35,9 +35,9 @@ from core.scss.storage import ScssFileStorage, find_file class ScssProcessor(object): """ - If DEBUG mode enabled : compile the scss file - Else : give the path of the corresponding css supposed to already be compiled - Don't forget to use compilestatics to compile scss for production + If DEBUG mode enabled : compile the scss file + Else : give the path of the corresponding css supposed to already be compiled + Don't forget to use compilestatics to compile scss for production """ prefix = iri_to_uri(getattr(settings, "STATIC_URL", "/static/")) diff --git a/core/search_indexes.py b/core/search_indexes.py index 7bece290..b98dc67b 100644 --- a/core/search_indexes.py +++ b/core/search_indexes.py @@ -34,6 +34,7 @@ from forum.models import ForumMessage, ForumMessageMeta class UserIndex(indexes.SearchIndex, indexes.Indexable): text = indexes.CharField(document=True, use_template=True) auto = indexes.EdgeNgramField(use_template=True) + last_update = indexes.DateTimeField(model_attr="last_update") def get_model(self): return User @@ -45,6 +46,9 @@ class UserIndex(indexes.SearchIndex, indexes.Indexable): def get_updated_field(self): return "last_update" + def prepare_auto(self, obj): + return self.prepared_data["auto"].strip()[:245] + class IndexSignalProcessor(signals.BaseSignalProcessor): def setup(self): diff --git a/core/static/core/js/vue.global.prod.js b/core/static/core/js/vue.global.prod.js new file mode 100644 index 00000000..cc65afcd --- /dev/null +++ b/core/static/core/js/vue.global.prod.js @@ -0,0 +1 @@ +var Vue=function(e){"use strict";function t(e,t){const n=Object.create(null),o=e.split(",");for(let r=0;r!!n[e.toLowerCase()]:e=>!!n[e]}const n=t("Infinity,undefined,NaN,isFinite,isNaN,parseFloat,parseInt,decodeURI,decodeURIComponent,encodeURI,encodeURIComponent,Math,Number,Date,Array,Object,Boolean,String,RegExp,Map,Set,JSON,Intl,BigInt"),o=t("itemscope,allowfullscreen,formnovalidate,ismap,nomodule,novalidate,readonly");function r(e){return!!e||""===e}function s(e){if(N(e)){const t={};for(let n=0;n{if(e){const n=e.split(l);n.length>1&&(t[n[0].trim()]=n[1].trim())}})),t}function a(e){let t="";if(A(e))t=e;else if(N(e))for(let n=0;nd(e,t)))}const m=(e,t)=>t&&t.__v_isRef?m(e,t.value):E(t)?{[`Map(${t.size})`]:[...t.entries()].reduce(((e,[t,n])=>(e[`${t} =>`]=n,e)),{})}:$(t)?{[`Set(${t.size})`]:[...t.values()]}:!M(t)||N(t)||B(t)?t:String(t),g={},v=[],y=()=>{},b=()=>!1,_=/^on[^a-z]/,S=e=>_.test(e),x=e=>e.startsWith("onUpdate:"),C=Object.assign,w=(e,t)=>{const n=e.indexOf(t);n>-1&&e.splice(n,1)},k=Object.prototype.hasOwnProperty,T=(e,t)=>k.call(e,t),N=Array.isArray,E=e=>"[object Map]"===I(e),$=e=>"[object Set]"===I(e),R=e=>e instanceof Date,O=e=>"function"==typeof e,A=e=>"string"==typeof e,F=e=>"symbol"==typeof e,M=e=>null!==e&&"object"==typeof e,P=e=>M(e)&&O(e.then)&&O(e.catch),V=Object.prototype.toString,I=e=>V.call(e),B=e=>"[object Object]"===I(e),L=e=>A(e)&&"NaN"!==e&&"-"!==e[0]&&""+parseInt(e,10)===e,j=t(",key,ref,onVnodeBeforeMount,onVnodeMounted,onVnodeBeforeUpdate,onVnodeUpdated,onVnodeBeforeUnmount,onVnodeUnmounted"),U=e=>{const t=Object.create(null);return n=>t[n]||(t[n]=e(n))},H=/-(\w)/g,D=U((e=>e.replace(H,((e,t)=>t?t.toUpperCase():"")))),W=/\B([A-Z])/g,z=U((e=>e.replace(W,"-$1").toLowerCase())),K=U((e=>e.charAt(0).toUpperCase()+e.slice(1))),G=U((e=>e?`on${K(e)}`:"")),q=(e,t)=>!Object.is(e,t),J=(e,t)=>{for(let n=0;n{Object.defineProperty(e,t,{configurable:!0,enumerable:!1,value:n})},Y=e=>{const t=parseFloat(e);return isNaN(t)?e:t};let Q;let X;const ee=[];class te{constructor(e=!1){this.active=!0,this.effects=[],this.cleanups=[],!e&&X&&(this.parent=X,this.index=(X.scopes||(X.scopes=[])).push(this)-1)}run(e){if(this.active)try{return this.on(),e()}finally{this.off()}}on(){this.active&&(ee.push(this),X=this)}off(){this.active&&(ee.pop(),X=ee[ee.length-1])}stop(e){if(this.active){if(this.effects.forEach((e=>e.stop())),this.cleanups.forEach((e=>e())),this.scopes&&this.scopes.forEach((e=>e.stop(!0))),this.parent&&!e){const e=this.parent.scopes.pop();e&&e!==this&&(this.parent.scopes[this.index]=e,e.index=this.index)}this.active=!1}}}function ne(e,t){(t=t||X)&&t.active&&t.effects.push(e)}const oe=e=>{const t=new Set(e);return t.w=0,t.n=0,t},re=e=>(e.w&ce)>0,se=e=>(e.n&ce)>0,ie=new WeakMap;let le=0,ce=1;const ae=[];let ue;const pe=Symbol(""),fe=Symbol("");class de{constructor(e,t=null,n){this.fn=e,this.scheduler=t,this.active=!0,this.deps=[],ne(this,n)}run(){if(!this.active)return this.fn();if(!ae.includes(this))try{return ae.push(ue=this),ge.push(me),me=!0,ce=1<<++le,le<=30?(({deps:e})=>{if(e.length)for(let t=0;t{const{deps:t}=e;if(t.length){let n=0;for(let o=0;o0?ae[e-1]:void 0}}stop(){this.active&&(he(this),this.onStop&&this.onStop(),this.active=!1)}}function he(e){const{deps:t}=e;if(t.length){for(let n=0;n{("length"===t||t>=o)&&l.push(e)}));else switch(void 0!==n&&l.push(i.get(n)),t){case"add":N(e)?L(n)&&l.push(i.get("length")):(l.push(i.get(pe)),E(e)&&l.push(i.get(fe)));break;case"delete":N(e)||(l.push(i.get(pe)),E(e)&&l.push(i.get(fe)));break;case"set":E(e)&&l.push(i.get(pe))}if(1===l.length)l[0]&&Ce(l[0]);else{const e=[];for(const t of l)t&&e.push(...t);Ce(oe(e))}}function Ce(e,t){for(const n of N(e)?e:[...e])(n!==ue||n.allowRecurse)&&(n.scheduler?n.scheduler():n.run())}const we=t("__proto__,__v_isRef,__isVue"),ke=new Set(Object.getOwnPropertyNames(Symbol).map((e=>Symbol[e])).filter(F)),Te=Ae(),Ne=Ae(!1,!0),Ee=Ae(!0),$e=Ae(!0,!0),Re=Oe();function Oe(){const e={};return["includes","indexOf","lastIndexOf"].forEach((t=>{e[t]=function(...e){const n=yt(this);for(let t=0,r=this.length;t{e[t]=function(...e){ve();const n=yt(this)[t].apply(this,e);return ye(),n}})),e}function Ae(e=!1,t=!1){return function(n,o,r){if("__v_isReactive"===o)return!e;if("__v_isReadonly"===o)return e;if("__v_raw"===o&&r===(e?t?at:ct:t?lt:it).get(n))return n;const s=N(n);if(!e&&s&&T(Re,o))return Reflect.get(Re,o,r);const i=Reflect.get(n,o,r);if(F(o)?ke.has(o):we(o))return i;if(e||be(n,0,o),t)return i;if(wt(i)){return!s||!L(o)?i.value:i}return M(i)?e?dt(i):pt(i):i}}function Fe(e=!1){return function(t,n,o,r){let s=t[n];if(!e&&(o=yt(o),s=yt(s),!N(t)&&wt(s)&&!wt(o)))return s.value=o,!0;const i=N(t)&&L(n)?Number(n)!0,deleteProperty:(e,t)=>!0},Ve=C({},Me,{get:Ne,set:Fe(!0)}),Ie=C({},Pe,{get:$e}),Be=e=>e,Le=e=>Reflect.getPrototypeOf(e);function je(e,t,n=!1,o=!1){const r=yt(e=e.__v_raw),s=yt(t);t!==s&&!n&&be(r,0,t),!n&&be(r,0,s);const{has:i}=Le(r),l=o?Be:n?St:_t;return i.call(r,t)?l(e.get(t)):i.call(r,s)?l(e.get(s)):void(e!==r&&e.get(t))}function Ue(e,t=!1){const n=this.__v_raw,o=yt(n),r=yt(e);return e!==r&&!t&&be(o,0,e),!t&&be(o,0,r),e===r?n.has(e):n.has(e)||n.has(r)}function He(e,t=!1){return e=e.__v_raw,!t&&be(yt(e),0,pe),Reflect.get(e,"size",e)}function De(e){e=yt(e);const t=yt(this);return Le(t).has.call(t,e)||(t.add(e),xe(t,"add",e,e)),this}function We(e,t){t=yt(t);const n=yt(this),{has:o,get:r}=Le(n);let s=o.call(n,e);s||(e=yt(e),s=o.call(n,e));const i=r.call(n,e);return n.set(e,t),s?q(t,i)&&xe(n,"set",e,t):xe(n,"add",e,t),this}function ze(e){const t=yt(this),{has:n,get:o}=Le(t);let r=n.call(t,e);r||(e=yt(e),r=n.call(t,e)),o&&o.call(t,e);const s=t.delete(e);return r&&xe(t,"delete",e,void 0),s}function Ke(){const e=yt(this),t=0!==e.size,n=e.clear();return t&&xe(e,"clear",void 0,void 0),n}function Ge(e,t){return function(n,o){const r=this,s=r.__v_raw,i=yt(s),l=t?Be:e?St:_t;return!e&&be(i,0,pe),s.forEach(((e,t)=>n.call(o,l(e),l(t),r)))}}function qe(e,t,n){return function(...o){const r=this.__v_raw,s=yt(r),i=E(s),l="entries"===e||e===Symbol.iterator&&i,c="keys"===e&&i,a=r[e](...o),u=n?Be:t?St:_t;return!t&&be(s,0,c?fe:pe),{next(){const{value:e,done:t}=a.next();return t?{value:e,done:t}:{value:l?[u(e[0]),u(e[1])]:u(e),done:t}},[Symbol.iterator](){return this}}}}function Je(e){return function(...t){return"delete"!==e&&this}}function Ze(){const e={get(e){return je(this,e)},get size(){return He(this)},has:Ue,add:De,set:We,delete:ze,clear:Ke,forEach:Ge(!1,!1)},t={get(e){return je(this,e,!1,!0)},get size(){return He(this)},has:Ue,add:De,set:We,delete:ze,clear:Ke,forEach:Ge(!1,!0)},n={get(e){return je(this,e,!0)},get size(){return He(this,!0)},has(e){return Ue.call(this,e,!0)},add:Je("add"),set:Je("set"),delete:Je("delete"),clear:Je("clear"),forEach:Ge(!0,!1)},o={get(e){return je(this,e,!0,!0)},get size(){return He(this,!0)},has(e){return Ue.call(this,e,!0)},add:Je("add"),set:Je("set"),delete:Je("delete"),clear:Je("clear"),forEach:Ge(!0,!0)};return["keys","values","entries",Symbol.iterator].forEach((r=>{e[r]=qe(r,!1,!1),n[r]=qe(r,!0,!1),t[r]=qe(r,!1,!0),o[r]=qe(r,!0,!0)})),[e,n,t,o]}const[Ye,Qe,Xe,et]=Ze();function tt(e,t){const n=t?e?et:Xe:e?Qe:Ye;return(t,o,r)=>"__v_isReactive"===o?!e:"__v_isReadonly"===o?e:"__v_raw"===o?t:Reflect.get(T(n,o)&&o in t?n:t,o,r)}const nt={get:tt(!1,!1)},ot={get:tt(!1,!0)},rt={get:tt(!0,!1)},st={get:tt(!0,!0)},it=new WeakMap,lt=new WeakMap,ct=new WeakMap,at=new WeakMap;function ut(e){return e.__v_skip||!Object.isExtensible(e)?0:function(e){switch(e){case"Object":case"Array":return 1;case"Map":case"Set":case"WeakMap":case"WeakSet":return 2;default:return 0}}((e=>I(e).slice(8,-1))(e))}function pt(e){return e&&e.__v_isReadonly?e:ht(e,!1,Me,nt,it)}function ft(e){return ht(e,!1,Ve,ot,lt)}function dt(e){return ht(e,!0,Pe,rt,ct)}function ht(e,t,n,o,r){if(!M(e))return e;if(e.__v_raw&&(!t||!e.__v_isReactive))return e;const s=r.get(e);if(s)return s;const i=ut(e);if(0===i)return e;const l=new Proxy(e,2===i?o:n);return r.set(e,l),l}function mt(e){return gt(e)?mt(e.__v_raw):!(!e||!e.__v_isReactive)}function gt(e){return!(!e||!e.__v_isReadonly)}function vt(e){return mt(e)||gt(e)}function yt(e){const t=e&&e.__v_raw;return t?yt(t):e}function bt(e){return Z(e,"__v_skip",!0),e}const _t=e=>M(e)?pt(e):e,St=e=>M(e)?dt(e):e;function xt(e){_e()&&((e=yt(e)).dep||(e.dep=oe()),Se(e.dep))}function Ct(e,t){(e=yt(e)).dep&&Ce(e.dep)}function wt(e){return Boolean(e&&!0===e.__v_isRef)}function kt(e){return Tt(e,!1)}function Tt(e,t){return wt(e)?e:new Nt(e,t)}class Nt{constructor(e,t){this._shallow=t,this.dep=void 0,this.__v_isRef=!0,this._rawValue=t?e:yt(e),this._value=t?e:_t(e)}get value(){return xt(this),this._value}set value(e){e=this._shallow?e:yt(e),q(e,this._rawValue)&&(this._rawValue=e,this._value=this._shallow?e:_t(e),Ct(this))}}function Et(e){return wt(e)?e.value:e}const $t={get:(e,t,n)=>Et(Reflect.get(e,t,n)),set:(e,t,n,o)=>{const r=e[t];return wt(r)&&!wt(n)?(r.value=n,!0):Reflect.set(e,t,n,o)}};function Rt(e){return mt(e)?e:new Proxy(e,$t)}class Ot{constructor(e){this.dep=void 0,this.__v_isRef=!0;const{get:t,set:n}=e((()=>xt(this)),(()=>Ct(this)));this._get=t,this._set=n}get value(){return this._get()}set value(e){this._set(e)}}class At{constructor(e,t){this._object=e,this._key=t,this.__v_isRef=!0}get value(){return this._object[this._key]}set value(e){this._object[this._key]=e}}function Ft(e,t){const n=e[t];return wt(n)?n:new At(e,t)}class Mt{constructor(e,t,n){this._setter=t,this.dep=void 0,this._dirty=!0,this.__v_isRef=!0,this.effect=new de(e,(()=>{this._dirty||(this._dirty=!0,Ct(this))})),this.__v_isReadonly=n}get value(){const e=yt(this);return xt(e),e._dirty&&(e._dirty=!1,e._value=e.effect.run()),e._value}set value(e){this._setter(e)}}function Pt(e,t){let n,o;const r=O(e);r?(n=e,o=y):(n=e.get,o=e.set);return new Mt(n,o,r||!o)}let Vt=[];function It(e,t,...n){const o=e.vnode.props||g;let r=n;const s=t.startsWith("update:"),i=s&&t.slice(7);if(i&&i in o){const e=`${"modelValue"===i?"model":i}Modifiers`,{number:t,trim:s}=o[e]||g;s?r=n.map((e=>e.trim())):t&&(r=n.map(Y))}let l,c=o[l=G(t)]||o[l=G(D(t))];!c&&s&&(c=o[l=G(z(t))]),c&&Rr(c,e,6,r);const a=o[l+"Once"];if(a){if(e.emitted){if(e.emitted[l])return}else e.emitted={};e.emitted[l]=!0,Rr(a,e,6,r)}}function Bt(e,t,n=!1){const o=t.emitsCache,r=o.get(e);if(void 0!==r)return r;const s=e.emits;let i={},l=!1;if(!O(e)){const o=e=>{const n=Bt(e,t,!0);n&&(l=!0,C(i,n))};!n&&t.mixins.length&&t.mixins.forEach(o),e.extends&&o(e.extends),e.mixins&&e.mixins.forEach(o)}return s||l?(N(s)?s.forEach((e=>i[e]=null)):C(i,s),o.set(e,i),i):(o.set(e,null),null)}function Lt(e,t){return!(!e||!S(t))&&(t=t.slice(2).replace(/Once$/,""),T(e,t[0].toLowerCase()+t.slice(1))||T(e,z(t))||T(e,t))}let jt=null,Ut=null;function Ht(e){const t=jt;return jt=e,Ut=e&&e.type.__scopeId||null,t}function Dt(e,t=jt,n){if(!t)return e;if(e._n)return e;const o=(...n)=>{o._d&&jo(-1);const r=Ht(t),s=e(...n);return Ht(r),o._d&&jo(1),s};return o._n=!0,o._c=!0,o._d=!0,o}function Wt(e){const{type:t,vnode:n,proxy:o,withProxy:r,props:s,propsOptions:[i],slots:l,attrs:c,emit:a,render:u,renderCache:p,data:f,setupState:d,ctx:h,inheritAttrs:m}=e;let g,v;const y=Ht(e);try{if(4&n.shapeFlag){const e=r||o;g=Xo(u.call(e,e,p,s,d,f,h)),v=c}else{const e=t;0,g=Xo(e(s,e.length>1?{attrs:c,slots:l,emit:a}:null)),v=t.props?c:zt(c)}}catch(_){Po.length=0,Or(_,e,1),g=Jo(Fo)}let b=g;if(v&&!1!==m){const e=Object.keys(v),{shapeFlag:t}=b;e.length&&7&t&&(i&&e.some(x)&&(v=Kt(v,i)),b=Yo(b,v))}return n.dirs&&(b.dirs=b.dirs?b.dirs.concat(n.dirs):n.dirs),n.transition&&(b.transition=n.transition),g=b,Ht(y),g}const zt=e=>{let t;for(const n in e)("class"===n||"style"===n||S(n))&&((t||(t={}))[n]=e[n]);return t},Kt=(e,t)=>{const n={};for(const o in e)x(o)&&o.slice(9)in t||(n[o]=e[o]);return n};function Gt(e,t,n){const o=Object.keys(t);if(o.length!==Object.keys(e).length)return!0;for(let r=0;r0?(Zt(e,"onPending"),Zt(e,"onFallback"),a(null,e.ssFallback,t,n,o,null,s,i),en(f,e.ssFallback)):f.resolve()}(t,n,o,r,s,i,l,c,a):function(e,t,n,o,r,s,i,l,{p:c,um:a,o:{createElement:u}}){const p=t.suspense=e.suspense;p.vnode=t,t.el=e.el;const f=t.ssContent,d=t.ssFallback,{activeBranch:h,pendingBranch:m,isInFallback:g,isHydrating:v}=p;if(m)p.pendingBranch=f,Wo(f,m)?(c(m,f,p.hiddenContainer,null,r,p,s,i,l),p.deps<=0?p.resolve():g&&(c(h,d,n,o,r,null,s,i,l),en(p,d))):(p.pendingId++,v?(p.isHydrating=!1,p.activeBranch=m):a(m,r,p),p.deps=0,p.effects.length=0,p.hiddenContainer=u("div"),g?(c(null,f,p.hiddenContainer,null,r,p,s,i,l),p.deps<=0?p.resolve():(c(h,d,n,o,r,null,s,i,l),en(p,d))):h&&Wo(f,h)?(c(h,f,n,o,r,p,s,i,l),p.resolve(!0)):(c(null,f,p.hiddenContainer,null,r,p,s,i,l),p.deps<=0&&p.resolve()));else if(h&&Wo(f,h))c(h,f,n,o,r,p,s,i,l),en(p,f);else if(Zt(t,"onPending"),p.pendingBranch=f,p.pendingId++,c(null,f,p.hiddenContainer,null,r,p,s,i,l),p.deps<=0)p.resolve();else{const{timeout:e,pendingId:t}=p;e>0?setTimeout((()=>{p.pendingId===t&&p.fallback(d)}),e):0===e&&p.fallback(d)}}(e,t,n,o,r,i,l,c,a)},hydrate:function(e,t,n,o,r,s,i,l,c){const a=t.suspense=Yt(t,o,n,e.parentNode,document.createElement("div"),null,r,s,i,l,!0),u=c(e,a.pendingBranch=t.ssContent,n,a,s,i);0===a.deps&&a.resolve();return u},create:Yt,normalize:function(e){const{shapeFlag:t,children:n}=e,o=32&t;e.ssContent=Qt(o?n.default:n),e.ssFallback=o?Qt(n.fallback):Jo(Fo)}};function Zt(e,t){const n=e.props&&e.props[t];O(n)&&n()}function Yt(e,t,n,o,r,s,i,l,c,a,u=!1){const{p:p,m:f,um:d,n:h,o:{parentNode:m,remove:g}}=a,v=Y(e.props&&e.props.timeout),y={vnode:e,parent:t,parentComponent:n,isSVG:i,container:o,hiddenContainer:r,anchor:s,deps:0,pendingId:0,timeout:"number"==typeof v?v:-1,activeBranch:null,pendingBranch:null,isInFallback:!0,isHydrating:u,isUnmounted:!1,effects:[],resolve(e=!1){const{vnode:t,activeBranch:n,pendingBranch:o,pendingId:r,effects:s,parentComponent:i,container:l}=y;if(y.isHydrating)y.isHydrating=!1;else if(!e){const e=n&&o.transition&&"out-in"===o.transition.mode;e&&(n.transition.afterLeave=()=>{r===y.pendingId&&f(o,l,t,0)});let{anchor:t}=y;n&&(t=h(n),d(n,i,y,!0)),e||f(o,l,t,0)}en(y,o),y.pendingBranch=null,y.isInFallback=!1;let c=y.parent,a=!1;for(;c;){if(c.pendingBranch){c.effects.push(...s),a=!0;break}c=c.parent}a||Jr(s),y.effects=[],Zt(t,"onResolve")},fallback(e){if(!y.pendingBranch)return;const{vnode:t,activeBranch:n,parentComponent:o,container:r,isSVG:s}=y;Zt(t,"onFallback");const i=h(n),a=()=>{y.isInFallback&&(p(null,e,r,i,o,null,s,l,c),en(y,e))},u=e.transition&&"out-in"===e.transition.mode;u&&(n.transition.afterLeave=a),y.isInFallback=!0,d(n,o,null,!0),u||a()},move(e,t,n){y.activeBranch&&f(y.activeBranch,e,t,n),y.container=e},next:()=>y.activeBranch&&h(y.activeBranch),registerDep(e,t){const n=!!y.pendingBranch;n&&y.deps++;const o=e.vnode.el;e.asyncDep.catch((t=>{Or(t,e,0)})).then((r=>{if(e.isUnmounted||y.isUnmounted||y.pendingId!==e.suspenseId)return;e.asyncResolved=!0;const{vnode:s}=e;yr(e,r,!1),o&&(s.el=o);const l=!o&&e.subTree.el;t(e,s,m(o||e.subTree.el),o?null:h(e.subTree),y,i,c),l&&g(l),qt(e,s.el),n&&0==--y.deps&&y.resolve()}))},unmount(e,t){y.isUnmounted=!0,y.activeBranch&&d(y.activeBranch,n,e,t),y.pendingBranch&&d(y.pendingBranch,n,e,t)}};return y}function Qt(e){let t;if(O(e)){const n=Lo&&e._c;n&&(e._d=!1,Io()),e=e(),n&&(e._d=!0,t=Vo,Bo())}if(N(e)){const t=function(e){let t;for(let n=0;nt!==e))),e}function Xt(e,t){t&&t.pendingBranch?N(e)?t.effects.push(...e):t.effects.push(e):Jr(e)}function en(e,t){e.activeBranch=t;const{vnode:n,parentComponent:o}=e,r=n.el=t.el;o&&o.subTree===n&&(o.vnode.el=r,qt(o,r))}function tn(e,t){if(ur){let n=ur.provides;const o=ur.parent&&ur.parent.provides;o===n&&(n=ur.provides=Object.create(o)),n[e]=t}else;}function nn(e,t,n=!1){const o=ur||jt;if(o){const r=null==o.parent?o.vnode.appContext&&o.vnode.appContext.provides:o.parent.provides;if(r&&e in r)return r[e];if(arguments.length>1)return n&&O(t)?t.call(o.proxy):t}}function on(){const e={isMounted:!1,isLeaving:!1,isUnmounting:!1,leavingVNodes:new Map};return En((()=>{e.isMounted=!0})),On((()=>{e.isUnmounting=!0})),e}const rn=[Function,Array],sn={name:"BaseTransition",props:{mode:String,appear:Boolean,persisted:Boolean,onBeforeEnter:rn,onEnter:rn,onAfterEnter:rn,onEnterCancelled:rn,onBeforeLeave:rn,onLeave:rn,onAfterLeave:rn,onLeaveCancelled:rn,onBeforeAppear:rn,onAppear:rn,onAfterAppear:rn,onAppearCancelled:rn},setup(e,{slots:t}){const n=pr(),o=on();let r;return()=>{const s=t.default&&fn(t.default(),!0);if(!s||!s.length)return;const i=yt(e),{mode:l}=i,c=s[0];if(o.isLeaving)return an(c);const a=un(c);if(!a)return an(c);const u=cn(a,i,o,n);pn(a,u);const p=n.subTree,f=p&&un(p);let d=!1;const{getTransitionKey:h}=a.type;if(h){const e=h();void 0===r?r=e:e!==r&&(r=e,d=!0)}if(f&&f.type!==Fo&&(!Wo(a,f)||d)){const e=cn(f,i,o,n);if(pn(f,e),"out-in"===l)return o.isLeaving=!0,e.afterLeave=()=>{o.isLeaving=!1,n.update()},an(c);"in-out"===l&&a.type!==Fo&&(e.delayLeave=(e,t,n)=>{ln(o,f)[String(f.key)]=f,e._leaveCb=()=>{t(),e._leaveCb=void 0,delete u.delayedLeave},u.delayedLeave=n})}return c}}};function ln(e,t){const{leavingVNodes:n}=e;let o=n.get(t.type);return o||(o=Object.create(null),n.set(t.type,o)),o}function cn(e,t,n,o){const{appear:r,mode:s,persisted:i=!1,onBeforeEnter:l,onEnter:c,onAfterEnter:a,onEnterCancelled:u,onBeforeLeave:p,onLeave:f,onAfterLeave:d,onLeaveCancelled:h,onBeforeAppear:m,onAppear:g,onAfterAppear:v,onAppearCancelled:y}=t,b=String(e.key),_=ln(n,e),S=(e,t)=>{e&&Rr(e,o,9,t)},x={mode:s,persisted:i,beforeEnter(t){let o=l;if(!n.isMounted){if(!r)return;o=m||l}t._leaveCb&&t._leaveCb(!0);const s=_[b];s&&Wo(e,s)&&s.el._leaveCb&&s.el._leaveCb(),S(o,[t])},enter(e){let t=c,o=a,s=u;if(!n.isMounted){if(!r)return;t=g||c,o=v||a,s=y||u}let i=!1;const l=e._enterCb=t=>{i||(i=!0,S(t?s:o,[e]),x.delayedLeave&&x.delayedLeave(),e._enterCb=void 0)};t?(t(e,l),t.length<=1&&l()):l()},leave(t,o){const r=String(e.key);if(t._enterCb&&t._enterCb(!0),n.isUnmounting)return o();S(p,[t]);let s=!1;const i=t._leaveCb=n=>{s||(s=!0,o(),S(n?h:d,[t]),t._leaveCb=void 0,_[r]===e&&delete _[r])};_[r]=e,f?(f(t,i),f.length<=1&&i()):i()},clone:e=>cn(e,t,n,o)};return x}function an(e){if(gn(e))return(e=Yo(e)).children=null,e}function un(e){return gn(e)?e.children?e.children[0]:void 0:e}function pn(e,t){6&e.shapeFlag&&e.component?pn(e.component.subTree,t):128&e.shapeFlag?(e.ssContent.transition=t.clone(e.ssContent),e.ssFallback.transition=t.clone(e.ssFallback)):e.transition=t}function fn(e,t=!1){let n=[],o=0;for(let r=0;r1)for(let r=0;r!!e.type.__asyncLoader;function mn(e,{vnode:{ref:t,props:n,children:o}}){const r=Jo(e,n,o);return r.ref=t,r}const gn=e=>e.type.__isKeepAlive,vn={name:"KeepAlive",__isKeepAlive:!0,props:{include:[String,RegExp,Array],exclude:[String,RegExp,Array],max:[String,Number]},setup(e,{slots:t}){const n=pr(),o=n.ctx;if(!o.renderer)return t.default;const r=new Map,s=new Set;let i=null;const l=n.suspense,{renderer:{p:c,m:a,um:u,o:{createElement:p}}}=o,f=p("div");function d(e){Cn(e),u(e,n,l)}function h(e){r.forEach(((t,n)=>{const o=wr(t.type);!o||e&&e(o)||m(n)}))}function m(e){const t=r.get(e);i&&t.type===i.type?i&&Cn(i):d(t),r.delete(e),s.delete(e)}o.activate=(e,t,n,o,r)=>{const s=e.component;a(e,t,n,0,l),c(s.vnode,e,t,n,s,l,o,e.slotScopeIds,r),mo((()=>{s.isDeactivated=!1,s.a&&J(s.a);const t=e.props&&e.props.onVnodeMounted;t&&_o(t,s.parent,e)}),l)},o.deactivate=e=>{const t=e.component;a(e,f,null,1,l),mo((()=>{t.da&&J(t.da);const n=e.props&&e.props.onVnodeUnmounted;n&&_o(n,t.parent,e),t.isDeactivated=!0}),l)},ns((()=>[e.include,e.exclude]),(([e,t])=>{e&&h((t=>yn(e,t))),t&&h((e=>!yn(t,e)))}),{flush:"post",deep:!0});let g=null;const v=()=>{null!=g&&r.set(g,wn(n.subTree))};return En(v),Rn(v),On((()=>{r.forEach((e=>{const{subTree:t,suspense:o}=n,r=wn(t);if(e.type!==r.type)d(e);else{Cn(r);const e=r.component.da;e&&mo(e,o)}}))})),()=>{if(g=null,!t.default)return null;const n=t.default(),o=n[0];if(n.length>1)return i=null,n;if(!(Do(o)&&(4&o.shapeFlag||128&o.shapeFlag)))return i=null,o;let l=wn(o);const c=l.type,a=wr(hn(l)?l.type.__asyncResolved||{}:c),{include:u,exclude:p,max:f}=e;if(u&&(!a||!yn(u,a))||p&&a&&yn(p,a))return i=l,o;const d=null==l.key?c:l.key,h=r.get(d);return l.el&&(l=Yo(l),128&o.shapeFlag&&(o.ssContent=l)),g=d,h?(l.el=h.el,l.component=h.component,l.transition&&pn(l,l.transition),l.shapeFlag|=512,s.delete(d),s.add(d)):(s.add(d),f&&s.size>parseInt(f,10)&&m(s.values().next().value)),l.shapeFlag|=256,i=l,o}}};function yn(e,t){return N(e)?e.some((e=>yn(e,t))):A(e)?e.split(",").indexOf(t)>-1:!!e.test&&e.test(t)}function bn(e,t){Sn(e,"a",t)}function _n(e,t){Sn(e,"da",t)}function Sn(e,t,n=ur){const o=e.__wdc||(e.__wdc=()=>{let t=n;for(;t;){if(t.isDeactivated)return;t=t.parent}e()});if(kn(t,o,n),n){let e=n.parent;for(;e&&e.parent;)gn(e.parent.vnode)&&xn(o,t,n,e),e=e.parent}}function xn(e,t,n,o){const r=kn(t,e,o,!0);An((()=>{w(o[t],r)}),n)}function Cn(e){let t=e.shapeFlag;256&t&&(t-=256),512&t&&(t-=512),e.shapeFlag=t}function wn(e){return 128&e.shapeFlag?e.ssContent:e}function kn(e,t,n=ur,o=!1){if(n){const r=n[e]||(n[e]=[]),s=t.__weh||(t.__weh=(...o)=>{if(n.isUnmounted)return;ve(),fr(n);const r=Rr(t,n,e,o);return dr(),ye(),r});return o?r.unshift(s):r.push(s),s}}const Tn=e=>(t,n=ur)=>(!vr||"sp"===e)&&kn(e,t,n),Nn=Tn("bm"),En=Tn("m"),$n=Tn("bu"),Rn=Tn("u"),On=Tn("bum"),An=Tn("um"),Fn=Tn("sp"),Mn=Tn("rtg"),Pn=Tn("rtc");function Vn(e,t=ur){kn("ec",e,t)}let In=!0;function Bn(e){const t=Un(e),n=e.proxy,o=e.ctx;In=!1,t.beforeCreate&&Ln(t.beforeCreate,e,"bc");const{data:r,computed:s,methods:i,watch:l,provide:c,inject:a,created:u,beforeMount:p,mounted:f,beforeUpdate:d,updated:h,activated:m,deactivated:g,beforeUnmount:v,unmounted:b,render:_,renderTracked:S,renderTriggered:x,errorCaptured:C,serverPrefetch:w,expose:k,inheritAttrs:T,components:E,directives:$}=t;if(a&&function(e,t,n=y,o=!1){N(e)&&(e=zn(e));for(const r in e){const n=e[r];let s;s=M(n)?"default"in n?nn(n.from||r,n.default,!0):nn(n.from||r):nn(n),wt(s)&&o?Object.defineProperty(t,r,{enumerable:!0,configurable:!0,get:()=>s.value,set:e=>s.value=e}):t[r]=s}}(a,o,null,e.appContext.config.unwrapInjectedRef),i)for(const y in i){const e=i[y];O(e)&&(o[y]=e.bind(n))}if(r){const t=r.call(n,n);M(t)&&(e.data=pt(t))}if(In=!0,s)for(const N in s){const e=s[N],t=Pt({get:O(e)?e.bind(n,n):O(e.get)?e.get.bind(n,n):y,set:!O(e)&&O(e.set)?e.set.bind(n):y});Object.defineProperty(o,N,{enumerable:!0,configurable:!0,get:()=>t.value,set:e=>t.value=e})}if(l)for(const y in l)jn(l[y],o,n,y);if(c){const e=O(c)?c.call(n):c;Reflect.ownKeys(e).forEach((t=>{tn(t,e[t])}))}function R(e,t){N(t)?t.forEach((t=>e(t.bind(n)))):t&&e(t.bind(n))}if(u&&Ln(u,e,"c"),R(Nn,p),R(En,f),R($n,d),R(Rn,h),R(bn,m),R(_n,g),R(Vn,C),R(Pn,S),R(Mn,x),R(On,v),R(An,b),R(Fn,w),N(k))if(k.length){const t=e.exposed||(e.exposed={});k.forEach((e=>{Object.defineProperty(t,e,{get:()=>n[e],set:t=>n[e]=t})}))}else e.exposed||(e.exposed={});_&&e.render===y&&(e.render=_),null!=T&&(e.inheritAttrs=T),E&&(e.components=E),$&&(e.directives=$)}function Ln(e,t,n){Rr(N(e)?e.map((e=>e.bind(t.proxy))):e.bind(t.proxy),t,n)}function jn(e,t,n,o){const r=o.includes(".")?ss(n,o):()=>n[o];if(A(e)){const n=t[e];O(n)&&ns(r,n)}else if(O(e))ns(r,e.bind(n));else if(M(e))if(N(e))e.forEach((e=>jn(e,t,n,o)));else{const o=O(e.handler)?e.handler.bind(n):t[e.handler];O(o)&&ns(r,o,e)}}function Un(e){const t=e.type,{mixins:n,extends:o}=t,{mixins:r,optionsCache:s,config:{optionMergeStrategies:i}}=e.appContext,l=s.get(t);let c;return l?c=l:r.length||n||o?(c={},r.length&&r.forEach((e=>Hn(c,e,i,!0))),Hn(c,t,i)):c=t,s.set(t,c),c}function Hn(e,t,n,o=!1){const{mixins:r,extends:s}=t;s&&Hn(e,s,n,!0),r&&r.forEach((t=>Hn(e,t,n,!0)));for(const i in t)if(o&&"expose"===i);else{const o=Dn[i]||n&&n[i];e[i]=o?o(e[i],t[i]):t[i]}return e}const Dn={data:Wn,props:Gn,emits:Gn,methods:Gn,computed:Gn,beforeCreate:Kn,created:Kn,beforeMount:Kn,mounted:Kn,beforeUpdate:Kn,updated:Kn,beforeDestroy:Kn,beforeUnmount:Kn,destroyed:Kn,unmounted:Kn,activated:Kn,deactivated:Kn,errorCaptured:Kn,serverPrefetch:Kn,components:Gn,directives:Gn,watch:function(e,t){if(!e)return t;if(!t)return e;const n=C(Object.create(null),e);for(const o in t)n[o]=Kn(e[o],t[o]);return n},provide:Wn,inject:function(e,t){return Gn(zn(e),zn(t))}};function Wn(e,t){return t?e?function(){return C(O(e)?e.call(this,this):e,O(t)?t.call(this,this):t)}:t:e}function zn(e){if(N(e)){const t={};for(let n=0;n{c=!0;const[n,o]=Zn(e,t,!0);C(i,n),o&&l.push(...o)};!n&&t.mixins.length&&t.mixins.forEach(o),e.extends&&o(e.extends),e.mixins&&e.mixins.forEach(o)}if(!s&&!c)return o.set(e,v),v;if(N(s))for(let u=0;u-1,n[1]=o<0||t-1||T(n,"default"))&&l.push(e)}}}const a=[i,l];return o.set(e,a),a}function Yn(e){return"$"!==e[0]}function Qn(e){const t=e&&e.toString().match(/^\s*function (\w+)/);return t?t[1]:null===e?"null":""}function Xn(e,t){return Qn(e)===Qn(t)}function eo(e,t){return N(t)?t.findIndex((t=>Xn(t,e))):O(t)&&Xn(t,e)?0:-1}const to=e=>"_"===e[0]||"$stable"===e,no=e=>N(e)?e.map(Xo):[Xo(e)],oo=(e,t,n)=>{const o=Dt(((...e)=>no(t(...e))),n);return o._c=!1,o},ro=(e,t,n)=>{const o=e._ctx;for(const r in e){if(to(r))continue;const n=e[r];if(O(n))t[r]=oo(0,n,o);else if(null!=n){const e=no(n);t[r]=()=>e}}},so=(e,t)=>{const n=no(t);e.slots.default=()=>n};function io(e,t,n,o){const r=e.dirs,s=t&&t.dirs;for(let i=0;i(s.has(e)||(e&&O(e.install)?(s.add(e),e.install(l,...t)):O(e)&&(s.add(e),e(l,...t))),l),mixin:e=>(r.mixins.includes(e)||r.mixins.push(e),l),component:(e,t)=>t?(r.components[e]=t,l):r.components[e],directive:(e,t)=>t?(r.directives[e]=t,l):r.directives[e],mount(s,c,a){if(!i){const u=Jo(n,o);return u.appContext=r,c&&t?t(u,s):e(u,s,a),i=!0,l._container=s,s.__vue_app__=l,xr(u.component)||u.component.proxy}},unmount(){i&&(e(null,l._container),delete l._container.__vue_app__)},provide:(e,t)=>(r.provides[e]=t,l)};return l}}let uo=!1;const po=e=>/svg/.test(e.namespaceURI)&&"foreignObject"!==e.tagName,fo=e=>8===e.nodeType;function ho(e){const{mt:t,p:n,o:{patchProp:o,nextSibling:r,parentNode:s,remove:i,insert:l,createComment:c}}=e,a=(n,o,i,l,c,m=!1)=>{const g=fo(n)&&"["===n.data,v=()=>d(n,o,i,l,c,g),{type:y,ref:b,shapeFlag:_}=o,S=n.nodeType;o.el=n;let x=null;switch(y){case Ao:3!==S?x=v():(n.data!==o.children&&(uo=!0,n.data=o.children),x=r(n));break;case Fo:x=8!==S||g?v():r(n);break;case Mo:if(1===S){x=n;const e=!o.children.length;for(let t=0;t{l=l||!!t.dynamicChildren;const{type:c,props:a,patchFlag:u,shapeFlag:f,dirs:d}=t,h="input"===c&&d||"option"===c;if(h||-1!==u){if(d&&io(t,null,n,"created"),a)if(h||!l||48&u)for(const t in a)(h&&t.endsWith("value")||S(t)&&!j(t))&&o(e,t,null,a[t],!1,void 0,n);else a.onClick&&o(e,"onClick",null,a.onClick,!1,void 0,n);let c;if((c=a&&a.onVnodeBeforeMount)&&_o(c,n,t),d&&io(t,null,n,"beforeMount"),((c=a&&a.onVnodeMounted)||d)&&Xt((()=>{c&&_o(c,n,t),d&&io(t,null,n,"mounted")}),r),16&f&&(!a||!a.innerHTML&&!a.textContent)){let o=p(e.firstChild,t,e,n,r,s,l);for(;o;){uo=!0;const e=o;o=o.nextSibling,i(e)}}else 8&f&&e.textContent!==t.children&&(uo=!0,e.textContent=t.children)}return e.nextSibling},p=(e,t,o,r,s,i,l)=>{l=l||!!t.dynamicChildren;const c=t.children,u=c.length;for(let p=0;p{const{slotScopeIds:u}=t;u&&(i=i?i.concat(u):u);const f=s(e),d=p(r(e),t,f,n,o,i,a);return d&&fo(d)&&"]"===d.data?r(t.anchor=d):(uo=!0,l(t.anchor=c("]"),f,d),d)},d=(e,t,o,l,c,a)=>{if(uo=!0,t.el=null,a){const t=h(e);for(;;){const n=r(e);if(!n||n===t)break;i(n)}}const u=r(e),p=s(e);return i(e),n(null,t,p,u,o,l,po(p),c),u},h=e=>{let t=0;for(;e;)if((e=r(e))&&fo(e)&&("["===e.data&&t++,"]"===e.data)){if(0===t)return r(e);t--}return e};return[(e,t)=>{if(!t.hasChildNodes())return n(null,e,t),void Yr();uo=!1,a(t.firstChild,e,null,null,null),Yr(),uo&&console.error("Hydration completed but contains mismatches.")},a]}const mo=Xt;function go(e){return yo(e)}function vo(e){return yo(e,ho)}function yo(e,t){(Q||(Q="undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:"undefined"!=typeof window?window:"undefined"!=typeof global?global:{})).__VUE__=!0;const{insert:n,remove:o,patchProp:r,createElement:s,createText:i,createComment:l,setText:c,setElementText:a,parentNode:u,nextSibling:p,setScopeId:f=y,cloneNode:d,insertStaticContent:h}=e,m=(e,t,n,o=null,r=null,s=null,i=!1,l=null,c=!!t.dynamicChildren)=>{if(e===t)return;e&&!Wo(e,t)&&(o=X(e),W(e,r,s,!0),e=null),-2===t.patchFlag&&(c=!1,t.dynamicChildren=null);const{type:a,ref:u,shapeFlag:p}=t;switch(a){case Ao:b(e,t,n,o);break;case Fo:_(e,t,n,o);break;case Mo:null==e&&S(t,n,o,i);break;case Oo:O(e,t,n,o,r,s,i,l,c);break;default:1&p?x(e,t,n,o,r,s,i,l,c):6&p?A(e,t,n,o,r,s,i,l,c):(64&p||128&p)&&a.process(e,t,n,o,r,s,i,l,c,ne)}null!=u&&r&&bo(u,e&&e.ref,s,t||e,!t)},b=(e,t,o,r)=>{if(null==e)n(t.el=i(t.children),o,r);else{const n=t.el=e.el;t.children!==e.children&&c(n,t.children)}},_=(e,t,o,r)=>{null==e?n(t.el=l(t.children||""),o,r):t.el=e.el},S=(e,t,n,o)=>{[e.el,e.anchor]=h(e.children,t,n,o)},x=(e,t,n,o,r,s,i,l,c)=>{i=i||"svg"===t.type,null==e?w(t,n,o,r,s,i,l,c):E(e,t,r,s,i,l,c)},w=(e,t,o,i,l,c,u,p)=>{let f,h;const{type:m,props:g,shapeFlag:v,transition:y,patchFlag:b,dirs:_}=e;if(e.el&&void 0!==d&&-1===b)f=e.el=d(e.el);else{if(f=e.el=s(e.type,c,g&&g.is,g),8&v?a(f,e.children):16&v&&N(e.children,f,null,i,l,c&&"foreignObject"!==m,u,p),_&&io(e,null,i,"created"),g){for(const t in g)"value"===t||j(t)||r(f,t,null,g[t],c,e.children,i,l,Y);"value"in g&&r(f,"value",null,g.value),(h=g.onVnodeBeforeMount)&&_o(h,i,e)}k(f,e,e.scopeId,u,i)}_&&io(e,null,i,"beforeMount");const S=(!l||l&&!l.pendingBranch)&&y&&!y.persisted;S&&y.beforeEnter(f),n(f,t,o),((h=g&&g.onVnodeMounted)||S||_)&&mo((()=>{h&&_o(h,i,e),S&&y.enter(f),_&&io(e,null,i,"mounted")}),l)},k=(e,t,n,o,r)=>{if(n&&f(e,n),o)for(let s=0;s{for(let a=c;a{const c=t.el=e.el;let{patchFlag:u,dynamicChildren:p,dirs:f}=t;u|=16&e.patchFlag;const d=e.props||g,h=t.props||g;let m;(m=h.onVnodeBeforeUpdate)&&_o(m,n,t,e),f&&io(t,e,n,"beforeUpdate");const v=s&&"foreignObject"!==t.type;if(p?$(e.dynamicChildren,p,c,n,o,v,i):l||B(e,t,c,null,n,o,v,i,!1),u>0){if(16&u)R(c,t,d,h,n,o,s);else if(2&u&&d.class!==h.class&&r(c,"class",null,h.class,s),4&u&&r(c,"style",d.style,h.style,s),8&u){const i=t.dynamicProps;for(let t=0;t{m&&_o(m,n,t,e),f&&io(t,e,n,"updated")}),o)},$=(e,t,n,o,r,s,i)=>{for(let l=0;l{if(n!==o){for(const c in o){if(j(c))continue;const a=o[c],u=n[c];a!==u&&"value"!==c&&r(e,c,u,a,l,t.children,s,i,Y)}if(n!==g)for(const c in n)j(c)||c in o||r(e,c,n[c],null,l,t.children,s,i,Y);"value"in o&&r(e,"value",n.value,o.value)}},O=(e,t,o,r,s,l,c,a,u)=>{const p=t.el=e?e.el:i(""),f=t.anchor=e?e.anchor:i("");let{patchFlag:d,dynamicChildren:h,slotScopeIds:m}=t;m&&(a=a?a.concat(m):m),null==e?(n(p,o,r),n(f,o,r),N(t.children,o,f,s,l,c,a,u)):d>0&&64&d&&h&&e.dynamicChildren?($(e.dynamicChildren,h,o,s,l,c,a),(null!=t.key||s&&t===s.subTree)&&So(e,t,!0)):B(e,t,o,f,s,l,c,a,u)},A=(e,t,n,o,r,s,i,l,c)=>{t.slotScopeIds=l,null==e?512&t.shapeFlag?r.ctx.activate(t,n,o,i,c):F(t,n,o,r,s,i,c):M(e,t,c)},F=(e,t,n,o,r,s,i)=>{const l=e.component=function(e,t,n){const o=e.type,r=(t?t.appContext:e.appContext)||cr,s={uid:ar++,vnode:e,type:o,parent:t,appContext:r,root:null,next:null,subTree:null,update:null,scope:new te(!0),render:null,proxy:null,exposed:null,exposeProxy:null,withProxy:null,provides:t?t.provides:Object.create(r.provides),accessCache:null,renderCache:[],components:null,directives:null,propsOptions:Zn(o,r),emitsOptions:Bt(o,r),emit:null,emitted:null,propsDefaults:g,inheritAttrs:o.inheritAttrs,ctx:g,data:g,props:g,attrs:g,slots:g,refs:g,setupState:g,setupContext:null,suspense:n,suspenseId:n?n.pendingId:0,asyncDep:null,asyncResolved:!1,isMounted:!1,isUnmounted:!1,isDeactivated:!1,bc:null,c:null,bm:null,m:null,bu:null,u:null,um:null,bum:null,da:null,a:null,rtg:null,rtc:null,ec:null,sp:null};s.ctx={_:s},s.root=t?t.root:s,s.emit=It.bind(null,s),e.ce&&e.ce(s);return s}(e,o,r);if(gn(e)&&(l.ctx.renderer=ne),function(e,t=!1){vr=t;const{props:n,children:o}=e.vnode,r=hr(e);(function(e,t,n,o=!1){const r={},s={};Z(s,zo,1),e.propsDefaults=Object.create(null),qn(e,t,r,s);for(const i in e.propsOptions[0])i in r||(r[i]=void 0);e.props=n?o?r:ft(r):e.type.props?r:s,e.attrs=s})(e,n,r,t),((e,t)=>{if(32&e.vnode.shapeFlag){const n=t._;n?(e.slots=yt(t),Z(t,"_",n)):ro(t,e.slots={})}else e.slots={},t&&so(e,t);Z(e.slots,zo,1)})(e,o);const s=r?function(e,t){const n=e.type;e.accessCache=Object.create(null),e.proxy=bt(new Proxy(e.ctx,ir));const{setup:o}=n;if(o){const n=e.setupContext=o.length>1?Sr(e):null;fr(e),ve();const r=$r(o,e,0,[e.props,n]);if(ye(),dr(),P(r)){if(r.then(dr,dr),t)return r.then((n=>{yr(e,n,t)})).catch((t=>{Or(t,e,0)}));e.asyncDep=r}else yr(e,r,t)}else _r(e,t)}(e,t):void 0;vr=!1}(l),l.asyncDep){if(r&&r.registerDep(l,V),!e.el){const e=l.subTree=Jo(Fo);_(null,e,t,n)}}else V(l,e,t,n,r,s,i)},M=(e,t,n)=>{const o=t.component=e.component;if(function(e,t,n){const{props:o,children:r,component:s}=e,{props:i,children:l,patchFlag:c}=t,a=s.emitsOptions;if(t.dirs||t.transition)return!0;if(!(n&&c>=0))return!(!r&&!l||l&&l.$stable)||o!==i&&(o?!i||Gt(o,i,a):!!i);if(1024&c)return!0;if(16&c)return o?Gt(o,i,a):!!i;if(8&c){const e=t.dynamicProps;for(let t=0;tPr&&Mr.splice(t,1)}(o.update),o.update()}else t.component=e.component,t.el=e.el,o.vnode=t},V=(e,t,n,o,r,s,i)=>{const l=new de((()=>{if(e.isMounted){let t,{next:n,bu:o,u:c,parent:a,vnode:p}=e,f=n;l.allowRecurse=!1,n?(n.el=p.el,I(e,n,i)):n=p,o&&J(o),(t=n.props&&n.props.onVnodeBeforeUpdate)&&_o(t,a,n,p),l.allowRecurse=!0;const d=Wt(e),h=e.subTree;e.subTree=d,m(h,d,u(h.el),X(h),e,r,s),n.el=d.el,null===f&&qt(e,d.el),c&&mo(c,r),(t=n.props&&n.props.onVnodeUpdated)&&mo((()=>_o(t,a,n,p)),r)}else{let i;const{el:c,props:a}=t,{bm:u,m:p,parent:f}=e,d=hn(t);if(l.allowRecurse=!1,u&&J(u),!d&&(i=a&&a.onVnodeBeforeMount)&&_o(i,f,t),l.allowRecurse=!0,c&&re){const n=()=>{e.subTree=Wt(e),re(c,e.subTree,e,r,null)};d?t.type.__asyncLoader().then((()=>!e.isUnmounted&&n())):n()}else{const i=e.subTree=Wt(e);m(null,i,n,o,e,r,s),t.el=i.el}if(p&&mo(p,r),!d&&(i=a&&a.onVnodeMounted)){const e=t;mo((()=>_o(i,f,e)),r)}256&t.shapeFlag&&e.a&&mo(e.a,r),e.isMounted=!0,t=n=o=null}}),(()=>Kr(e.update)),e.scope),c=e.update=l.run.bind(l);c.id=e.uid,l.allowRecurse=c.allowRecurse=!0,c()},I=(e,t,n)=>{t.component=e;const o=e.vnode.props;e.vnode=t,e.next=null,function(e,t,n,o){const{props:r,attrs:s,vnode:{patchFlag:i}}=e,l=yt(r),[c]=e.propsOptions;let a=!1;if(!(o||i>0)||16&i){let o;qn(e,t,r,s)&&(a=!0);for(const s in l)t&&(T(t,s)||(o=z(s))!==s&&T(t,o))||(c?!n||void 0===n[s]&&void 0===n[o]||(r[s]=Jn(c,l,s,void 0,e,!0)):delete r[s]);if(s!==l)for(const e in s)t&&T(t,e)||(delete s[e],a=!0)}else if(8&i){const n=e.vnode.dynamicProps;for(let o=0;o{const{vnode:o,slots:r}=e;let s=!0,i=g;if(32&o.shapeFlag){const e=t._;e?n&&1===e?s=!1:(C(r,t),n||1!==e||delete r._):(s=!t.$stable,ro(t,r)),i=t}else t&&(so(e,t),i={default:1});if(s)for(const l in r)to(l)||l in i||delete r[l]})(e,t.children,n),ve(),Zr(void 0,e.update),ye()},B=(e,t,n,o,r,s,i,l,c=!1)=>{const u=e&&e.children,p=e?e.shapeFlag:0,f=t.children,{patchFlag:d,shapeFlag:h}=t;if(d>0){if(128&d)return void U(u,f,n,o,r,s,i,l,c);if(256&d)return void L(u,f,n,o,r,s,i,l,c)}8&h?(16&p&&Y(u,r,s),f!==u&&a(n,f)):16&p?16&h?U(u,f,n,o,r,s,i,l,c):Y(u,r,s,!0):(8&p&&a(n,""),16&h&&N(f,n,o,r,s,i,l,c))},L=(e,t,n,o,r,s,i,l,c)=>{const a=(e=e||v).length,u=(t=t||v).length,p=Math.min(a,u);let f;for(f=0;fu?Y(e,r,s,!0,!1,p):N(t,n,o,r,s,i,l,c,p)},U=(e,t,n,o,r,s,i,l,c)=>{let a=0;const u=t.length;let p=e.length-1,f=u-1;for(;a<=p&&a<=f;){const o=e[a],u=t[a]=c?er(t[a]):Xo(t[a]);if(!Wo(o,u))break;m(o,u,n,null,r,s,i,l,c),a++}for(;a<=p&&a<=f;){const o=e[p],a=t[f]=c?er(t[f]):Xo(t[f]);if(!Wo(o,a))break;m(o,a,n,null,r,s,i,l,c),p--,f--}if(a>p){if(a<=f){const e=f+1,p=ef)for(;a<=p;)W(e[a],r,s,!0),a++;else{const d=a,h=a,g=new Map;for(a=h;a<=f;a++){const e=t[a]=c?er(t[a]):Xo(t[a]);null!=e.key&&g.set(e.key,a)}let y,b=0;const _=f-h+1;let S=!1,x=0;const C=new Array(_);for(a=0;a<_;a++)C[a]=0;for(a=d;a<=p;a++){const o=e[a];if(b>=_){W(o,r,s,!0);continue}let u;if(null!=o.key)u=g.get(o.key);else for(y=h;y<=f;y++)if(0===C[y-h]&&Wo(o,t[y])){u=y;break}void 0===u?W(o,r,s,!0):(C[u-h]=a+1,u>=x?x=u:S=!0,m(o,t[u],n,null,r,s,i,l,c),b++)}const w=S?function(e){const t=e.slice(),n=[0];let o,r,s,i,l;const c=e.length;for(o=0;o>1,e[n[l]]0&&(t[o]=n[s-1]),n[s]=o)}}s=n.length,i=n[s-1];for(;s-- >0;)n[s]=i,i=t[i];return n}(C):v;for(y=w.length-1,a=_-1;a>=0;a--){const e=h+a,p=t[e],f=e+1{const{el:i,type:l,transition:c,children:a,shapeFlag:u}=e;if(6&u)return void H(e.component.subTree,t,o,r);if(128&u)return void e.suspense.move(t,o,r);if(64&u)return void l.move(e,t,o,ne);if(l===Oo){n(i,t,o);for(let e=0;e{let s;for(;e&&e!==t;)s=p(e),n(e,o,r),e=s;n(t,o,r)})(e,t,o);if(2!==r&&1&u&&c)if(0===r)c.beforeEnter(i),n(i,t,o),mo((()=>c.enter(i)),s);else{const{leave:e,delayLeave:r,afterLeave:s}=c,l=()=>n(i,t,o),a=()=>{e(i,(()=>{l(),s&&s()}))};r?r(i,l,a):a()}else n(i,t,o)},W=(e,t,n,o=!1,r=!1)=>{const{type:s,props:i,ref:l,children:c,dynamicChildren:a,shapeFlag:u,patchFlag:p,dirs:f}=e;if(null!=l&&bo(l,null,n,e,!0),256&u)return void t.ctx.deactivate(e);const d=1&u&&f,h=!hn(e);let m;if(h&&(m=i&&i.onVnodeBeforeUnmount)&&_o(m,t,e),6&u)q(e.component,n,o);else{if(128&u)return void e.suspense.unmount(n,o);d&&io(e,null,t,"beforeUnmount"),64&u?e.type.remove(e,t,n,r,ne,o):a&&(s!==Oo||p>0&&64&p)?Y(a,t,n,!1,!0):(s===Oo&&384&p||!r&&16&u)&&Y(c,t,n),o&&K(e)}(h&&(m=i&&i.onVnodeUnmounted)||d)&&mo((()=>{m&&_o(m,t,e),d&&io(e,null,t,"unmounted")}),n)},K=e=>{const{type:t,el:n,anchor:r,transition:s}=e;if(t===Oo)return void G(n,r);if(t===Mo)return void(({el:e,anchor:t})=>{let n;for(;e&&e!==t;)n=p(e),o(e),e=n;o(t)})(e);const i=()=>{o(n),s&&!s.persisted&&s.afterLeave&&s.afterLeave()};if(1&e.shapeFlag&&s&&!s.persisted){const{leave:t,delayLeave:o}=s,r=()=>t(n,i);o?o(e.el,i,r):r()}else i()},G=(e,t)=>{let n;for(;e!==t;)n=p(e),o(e),e=n;o(t)},q=(e,t,n)=>{const{bum:o,scope:r,update:s,subTree:i,um:l}=e;o&&J(o),r.stop(),s&&(s.active=!1,W(i,e,t,n)),l&&mo(l,t),mo((()=>{e.isUnmounted=!0}),t),t&&t.pendingBranch&&!t.isUnmounted&&e.asyncDep&&!e.asyncResolved&&e.suspenseId===t.pendingId&&(t.deps--,0===t.deps&&t.resolve())},Y=(e,t,n,o=!1,r=!1,s=0)=>{for(let i=s;i6&e.shapeFlag?X(e.component.subTree):128&e.shapeFlag?e.suspense.next():p(e.anchor||e.el),ee=(e,t,n)=>{null==e?t._vnode&&W(t._vnode,null,null,!0):m(t._vnode||null,e,t,null,null,null,n),Yr(),t._vnode=e},ne={p:m,um:W,m:H,r:K,mt:F,mc:N,pc:B,pbc:$,n:X,o:e};let oe,re;return t&&([oe,re]=t(ne)),{render:ee,hydrate:oe,createApp:ao(ee,oe)}}function bo(e,t,n,o,r=!1){if(N(e))return void e.forEach(((e,s)=>bo(e,t&&(N(t)?t[s]:t),n,o,r)));if(hn(o)&&!r)return;const s=4&o.shapeFlag?xr(o.component)||o.component.proxy:o.el,i=r?null:s,{i:l,r:c}=e,a=t&&t.r,u=l.refs===g?l.refs={}:l.refs,p=l.setupState;if(null!=a&&a!==c&&(A(a)?(u[a]=null,T(p,a)&&(p[a]=null)):wt(a)&&(a.value=null)),A(c)){const e=()=>{u[c]=i,T(p,c)&&(p[c]=i)};i?(e.id=-1,mo(e,n)):e()}else if(wt(c)){const e=()=>{c.value=i};i?(e.id=-1,mo(e,n)):e()}else O(c)&&$r(c,l,12,[i,u])}function _o(e,t,n,o=null){Rr(e,t,7,[n,o])}function So(e,t,n=!1){const o=e.children,r=t.children;if(N(o)&&N(r))for(let s=0;se&&(e.disabled||""===e.disabled),Co=e=>"undefined"!=typeof SVGElement&&e instanceof SVGElement,wo=(e,t)=>{const n=e&&e.to;if(A(n)){if(t){return t(n)}return null}return n};function ko(e,t,n,{o:{insert:o},m:r},s=2){0===s&&o(e.targetAnchor,t,n);const{el:i,anchor:l,shapeFlag:c,children:a,props:u}=e,p=2===s;if(p&&o(i,t,n),(!p||xo(u))&&16&c)for(let f=0;f{16&v&&u(y,e,t,r,s,i,l,c)};g?b(n,a):p&&b(p,f)}else{t.el=e.el;const o=t.anchor=e.anchor,u=t.target=e.target,d=t.targetAnchor=e.targetAnchor,m=xo(e.props),v=m?n:u,y=m?o:d;if(i=i||Co(u),b?(f(e.dynamicChildren,b,v,r,s,i,l),So(e,t,!0)):c||p(e,t,v,y,r,s,i,l,!1),g)m||ko(t,n,o,a,1);else if((t.props&&t.props.to)!==(e.props&&e.props.to)){const e=t.target=wo(t.props,h);e&&ko(t,e,null,a,0)}else m&&ko(t,u,d,a,1)}},remove(e,t,n,o,{um:r,o:{remove:s}},i){const{shapeFlag:l,children:c,anchor:a,targetAnchor:u,target:p,props:f}=e;if(p&&s(u),(i||!xo(f))&&(s(a),16&l))for(let d=0;d0?Vo||v:null,Bo(),Lo>0&&Vo&&Vo.push(e),e}function Ho(e,t,n,o,r){return Uo(Jo(e,t,n,o,r,!0))}function Do(e){return!!e&&!0===e.__v_isVNode}function Wo(e,t){return e.type===t.type&&e.key===t.key}const zo="__vInternal",Ko=({key:e})=>null!=e?e:null,Go=({ref:e})=>null!=e?A(e)||wt(e)||O(e)?{i:jt,r:e}:e:null;function qo(e,t=null,n=null,o=0,r=null,s=(e===Oo?0:1),i=!1,l=!1){const c={__v_isVNode:!0,__v_skip:!0,type:e,props:t,key:t&&Ko(t),ref:t&&Go(t),scopeId:Ut,slotScopeIds:null,children:n,component:null,suspense:null,ssContent:null,ssFallback:null,dirs:null,transition:null,el:null,anchor:null,target:null,targetAnchor:null,staticCount:0,shapeFlag:s,patchFlag:o,dynamicProps:r,dynamicChildren:null,appContext:null};return l?(tr(c,n),128&s&&e.normalize(c)):n&&(c.shapeFlag|=A(n)?8:16),Lo>0&&!i&&Vo&&(c.patchFlag>0||6&s)&&32!==c.patchFlag&&Vo.push(c),c}const Jo=function(e,t=null,n=null,o=0,r=null,i=!1){e&&e!==Eo||(e=Fo);if(Do(e)){const o=Yo(e,t,!0);return n&&tr(o,n),o}l=e,O(l)&&"__vccOpts"in l&&(e=e.__vccOpts);var l;if(t){t=Zo(t);let{class:e,style:n}=t;e&&!A(e)&&(t.class=a(e)),M(n)&&(vt(n)&&!N(n)&&(n=C({},n)),t.style=s(n))}const c=A(e)?1:(e=>e.__isSuspense)(e)?128:(e=>e.__isTeleport)(e)?64:M(e)?4:O(e)?2:0;return qo(e,t,n,o,r,c,i,!0)};function Zo(e){return e?vt(e)||zo in e?C({},e):e:null}function Yo(e,t,n=!1){const{props:o,ref:r,patchFlag:s,children:i}=e,l=t?nr(o||{},t):o;return{__v_isVNode:!0,__v_skip:!0,type:e.type,props:l,key:l&&Ko(l),ref:t&&t.ref?n&&r?N(r)?r.concat(Go(t)):[r,Go(t)]:Go(t):r,scopeId:e.scopeId,slotScopeIds:e.slotScopeIds,children:i,target:e.target,targetAnchor:e.targetAnchor,staticCount:e.staticCount,shapeFlag:e.shapeFlag,patchFlag:t&&e.type!==Oo?-1===s?16:16|s:s,dynamicProps:e.dynamicProps,dynamicChildren:e.dynamicChildren,appContext:e.appContext,dirs:e.dirs,transition:e.transition,component:e.component,suspense:e.suspense,ssContent:e.ssContent&&Yo(e.ssContent),ssFallback:e.ssFallback&&Yo(e.ssFallback),el:e.el,anchor:e.anchor}}function Qo(e=" ",t=0){return Jo(Ao,null,e,t)}function Xo(e){return null==e||"boolean"==typeof e?Jo(Fo):N(e)?Jo(Oo,null,e.slice()):"object"==typeof e?er(e):Jo(Ao,null,String(e))}function er(e){return null===e.el||e.memo?e:Yo(e)}function tr(e,t){let n=0;const{shapeFlag:o}=e;if(null==t)t=null;else if(N(t))n=16;else if("object"==typeof t){if(65&o){const n=t.default;return void(n&&(n._c&&(n._d=!1),tr(e,n()),n._c&&(n._d=!0)))}{n=32;const o=t._;o||zo in t?3===o&&jt&&(1===jt.slots._?t._=1:(t._=2,e.patchFlag|=1024)):t._ctx=jt}}else O(t)?(t={default:t,_ctx:jt},n=32):(t=String(t),64&o?(n=16,t=[Qo(t)]):n=8);e.children=t,e.shapeFlag|=n}function nr(...e){const t={};for(let n=0;n!Do(e)||e.type!==Fo&&!(e.type===Oo&&!or(e.children))))?e:null}const rr=e=>e?hr(e)?xr(e)||e.proxy:rr(e.parent):null,sr=C(Object.create(null),{$:e=>e,$el:e=>e.vnode.el,$data:e=>e.data,$props:e=>e.props,$attrs:e=>e.attrs,$slots:e=>e.slots,$refs:e=>e.refs,$parent:e=>rr(e.parent),$root:e=>rr(e.root),$emit:e=>e.emit,$options:e=>Un(e),$forceUpdate:e=>()=>Kr(e.update),$nextTick:e=>zr.bind(e.proxy),$watch:e=>rs.bind(e)}),ir={get({_:e},t){const{ctx:n,setupState:o,data:r,props:s,accessCache:i,type:l,appContext:c}=e;let a;if("$"!==t[0]){const l=i[t];if(void 0!==l)switch(l){case 0:return o[t];case 1:return r[t];case 3:return n[t];case 2:return s[t]}else{if(o!==g&&T(o,t))return i[t]=0,o[t];if(r!==g&&T(r,t))return i[t]=1,r[t];if((a=e.propsOptions[0])&&T(a,t))return i[t]=2,s[t];if(n!==g&&T(n,t))return i[t]=3,n[t];In&&(i[t]=4)}}const u=sr[t];let p,f;return u?("$attrs"===t&&be(e,0,t),u(e)):(p=l.__cssModules)&&(p=p[t])?p:n!==g&&T(n,t)?(i[t]=3,n[t]):(f=c.config.globalProperties,T(f,t)?f[t]:void 0)},set({_:e},t,n){const{data:o,setupState:r,ctx:s}=e;if(r!==g&&T(r,t))r[t]=n;else if(o!==g&&T(o,t))o[t]=n;else if(T(e.props,t))return!1;return("$"!==t[0]||!(t.slice(1)in e))&&(s[t]=n,!0)},has({_:{data:e,setupState:t,accessCache:n,ctx:o,appContext:r,propsOptions:s}},i){let l;return void 0!==n[i]||e!==g&&T(e,i)||t!==g&&T(t,i)||(l=s[0])&&T(l,i)||T(o,i)||T(sr,i)||T(r.config.globalProperties,i)}},lr=C({},ir,{get(e,t){if(t!==Symbol.unscopables)return ir.get(e,t,e)},has:(e,t)=>"_"!==t[0]&&!n(t)}),cr=lo();let ar=0;let ur=null;const pr=()=>ur||jt,fr=e=>{ur=e,e.scope.on()},dr=()=>{ur&&ur.scope.off(),ur=null};function hr(e){return 4&e.vnode.shapeFlag}let mr,gr,vr=!1;function yr(e,t,n){O(t)?e.render=t:M(t)&&(e.setupState=Rt(t)),_r(e,n)}function br(e){mr=e,gr=e=>{e.render._rc&&(e.withProxy=new Proxy(e.ctx,lr))}}function _r(e,t,n){const o=e.type;if(!e.render){if(!t&&mr&&!o.render){const t=o.template;if(t){const{isCustomElement:n,compilerOptions:r}=e.appContext.config,{delimiters:s,compilerOptions:i}=o,l=C(C({isCustomElement:n,delimiters:s},r),i);o.render=mr(t,l)}}e.render=o.render||y,gr&&gr(e)}fr(e),ve(),Bn(e),ye(),dr()}function Sr(e){const t=t=>{e.exposed=t||{}};let n;return{get attrs(){return n||(n=function(e){return new Proxy(e.attrs,{get:(t,n)=>(be(e,0,"$attrs"),t[n])})}(e))},slots:e.slots,emit:e.emit,expose:t}}function xr(e){if(e.exposed)return e.exposeProxy||(e.exposeProxy=new Proxy(Rt(bt(e.exposed)),{get:(t,n)=>n in t?t[n]:n in sr?sr[n](e):void 0}))}const Cr=/(?:^|[-_])(\w)/g;function wr(e){return O(e)&&e.displayName||e.name}function kr(e,t,n=!1){let o=wr(t);if(!o&&t.__file){const e=t.__file.match(/([^/\\]+)\.\w+$/);e&&(o=e[1])}if(!o&&e&&e.parent){const n=e=>{for(const n in e)if(e[n]===t)return n};o=n(e.components||e.parent.type.components)||n(e.appContext.components)}return o?o.replace(Cr,(e=>e.toUpperCase())).replace(/[-_]/g,""):n?"App":"Anonymous"}const Tr=[];function Nr(e){const t=[],n=Object.keys(e);return n.slice(0,3).forEach((n=>{t.push(...Er(n,e[n]))})),n.length>3&&t.push(" ..."),t}function Er(e,t,n){return A(t)?(t=JSON.stringify(t),n?t:[`${e}=${t}`]):"number"==typeof t||"boolean"==typeof t||null==t?n?t:[`${e}=${t}`]:wt(t)?(t=Er(e,yt(t.value),!0),n?t:[`${e}=Ref<`,t,">"]):O(t)?[`${e}=fn${t.name?`<${t.name}>`:""}`]:(t=yt(t),n?t:[`${e}=`,t])}function $r(e,t,n,o){let r;try{r=o?e(...o):e()}catch(s){Or(s,t,n)}return r}function Rr(e,t,n,o){if(O(e)){const r=$r(e,t,n,o);return r&&P(r)&&r.catch((e=>{Or(e,t,n)})),r}const r=[];for(let s=0;s>>1;Qr(Mr[o])Qr(e)-Qr(t))),Ur=0;Urnull==e.id?1/0:e.id;function Xr(e){Fr=!1,Ar=!0,Zr(e),Mr.sort(((e,t)=>Qr(e)-Qr(t)));try{for(Pr=0;Pre.value,c=!!e._shallow):mt(e)?(i=()=>e,o=!0):N(e)?(a=!0,c=e.some(mt),i=()=>e.map((e=>wt(e)?e.value:mt(e)?is(e):O(e)?$r(e,s,2):void 0))):i=O(e)?t?()=>$r(e,s,2):()=>{if(!s||!s.isUnmounted)return l&&l(),Rr(e,s,3,[u])}:y,t&&o){const e=i;i=()=>is(e())}let u=e=>{l=h.onStop=()=>{$r(e,s,4)}},p=a?[]:ts;const f=()=>{if(h.active)if(t){const e=h.run();(o||c||(a?e.some(((e,t)=>q(e,p[t]))):q(e,p)))&&(l&&l(),Rr(t,s,3,[e,p===ts?void 0:p,u]),p=e)}else h.run()};let d;f.allowRecurse=!!t,d="sync"===r?f:"post"===r?()=>mo(f,s&&s.suspense):()=>{!s||s.isMounted?function(e){qr(e,Ir,Vr,Br)}(f):f()};const h=new de(i,d);return t?n?f():p=h.run():"post"===r?mo(h.run.bind(h),s&&s.suspense):h.run(),()=>{h.stop(),s&&s.scope&&w(s.scope.effects,h)}}function rs(e,t,n){const o=this.proxy,r=A(e)?e.includes(".")?ss(o,e):()=>o[e]:e.bind(o,o);let s;O(t)?s=t:(s=t.handler,n=t);const i=ur;fr(this);const l=os(r,s.bind(o),n);return i?fr(i):dr(),l}function ss(e,t){const n=t.split(".");return()=>{let t=e;for(let e=0;e{is(e,t)}));else if(B(e))for(const n in e)is(e[n],t);return e}function ls(){const e=pr();return e.setupContext||(e.setupContext=Sr(e))}function cs(e,t,n){const o=arguments.length;return 2===o?M(t)&&!N(t)?Do(t)?Jo(e,null,[t]):Jo(e,t):Jo(e,null,t):(o>3?n=Array.prototype.slice.call(arguments,2):3===o&&Do(n)&&(n=[n]),Jo(e,t,n))}const as=Symbol("");function us(e,t){const n=e.memo;if(n.length!=t.length)return!1;for(let o=0;o0&&Vo&&Vo.push(e),!0}const ps="3.2.18",fs="undefined"!=typeof document?document:null,ds=new Map,hs={insert:(e,t,n)=>{t.insertBefore(e,n||null)},remove:e=>{const t=e.parentNode;t&&t.removeChild(e)},createElement:(e,t,n,o)=>{const r=t?fs.createElementNS("http://www.w3.org/2000/svg",e):fs.createElement(e,n?{is:n}:void 0);return"select"===e&&o&&null!=o.multiple&&r.setAttribute("multiple",o.multiple),r},createText:e=>fs.createTextNode(e),createComment:e=>fs.createComment(e),setText:(e,t)=>{e.nodeValue=t},setElementText:(e,t)=>{e.textContent=t},parentNode:e=>e.parentNode,nextSibling:e=>e.nextSibling,querySelector:e=>fs.querySelector(e),setScopeId(e,t){e.setAttribute(t,"")},cloneNode(e){const t=e.cloneNode(!0);return"_value"in e&&(t._value=e._value),t},insertStaticContent(e,t,n,o){const r=n?n.previousSibling:t.lastChild;let s=ds.get(e);if(!s){const t=fs.createElement("template");if(t.innerHTML=o?`${e}`:e,s=t.content,o){const e=s.firstChild;for(;e.firstChild;)s.appendChild(e.firstChild);s.removeChild(e)}ds.set(e,s)}return t.insertBefore(s.cloneNode(!0),n),[r?r.nextSibling:t.firstChild,n?n.previousSibling:t.lastChild]}};const ms=/\s*!important$/;function gs(e,t,n){if(N(n))n.forEach((n=>gs(e,t,n)));else if(t.startsWith("--"))e.setProperty(t,n);else{const o=function(e,t){const n=ys[t];if(n)return n;let o=D(t);if("filter"!==o&&o in e)return ys[t]=o;o=K(o);for(let r=0;rdocument.createEvent("Event").timeStamp&&(_s=()=>performance.now());const e=navigator.userAgent.match(/firefox\/(\d+)/i);Ss=!!(e&&Number(e[1])<=53)}let xs=0;const Cs=Promise.resolve(),ws=()=>{xs=0};function ks(e,t,n,o){e.addEventListener(t,n,o)}function Ts(e,t,n,o,r=null){const s=e._vei||(e._vei={}),i=s[t];if(o&&i)i.value=o;else{const[n,l]=function(e){let t;if(Ns.test(e)){let n;for(t={};n=e.match(Ns);)e=e.slice(0,e.length-n[0].length),t[n[0].toLowerCase()]=!0}return[z(e.slice(2)),t]}(t);if(o){ks(e,n,s[t]=function(e,t){const n=e=>{const o=e.timeStamp||_s();(Ss||o>=n.attached-1)&&Rr(function(e,t){if(N(t)){const n=e.stopImmediatePropagation;return e.stopImmediatePropagation=()=>{n.call(e),e._stopped=!0},t.map((e=>t=>!t._stopped&&e(t)))}return t}(e,n.value),t,5,[e])};return n.value=e,n.attached=(()=>xs||(Cs.then(ws),xs=_s()))(),n}(o,r),l)}else i&&(!function(e,t,n,o){e.removeEventListener(t,n,o)}(e,n,i,l),s[t]=void 0)}}const Ns=/(?:Once|Passive|Capture)$/;const Es=/^on[a-z]/;function $s(e,t){const n=dn(e);class o extends Os{constructor(e){super(n,e,t)}}return o.def=n,o}const Rs="undefined"!=typeof HTMLElement?HTMLElement:class{};class Os extends Rs{constructor(e,t={},n){super(),this._def=e,this._props=t,this._instance=null,this._connected=!1,this._resolved=!1,this._numberProps=null,this.shadowRoot&&n?n(this._createVNode(),this.shadowRoot):this.attachShadow({mode:"open"});for(let o=0;o{for(const t of e)this._setAttr(t.attributeName)})).observe(this,{attributes:!0})}connectedCallback(){this._connected=!0,this._instance||(this._resolveDef(),this._update())}disconnectedCallback(){this._connected=!1,zr((()=>{this._connected||(Ni(null,this.shadowRoot),this._instance=null)}))}_resolveDef(){if(this._resolved)return;const e=e=>{this._resolved=!0;const{props:t,styles:n}=e,o=!N(t),r=t?o?Object.keys(t):t:[];let s;if(o)for(const i in this._props){const e=t[i];(e===Number||e&&e.type===Number)&&(this._props[i]=Y(this._props[i]),(s||(s=Object.create(null)))[i]=!0)}s&&(this._numberProps=s,this._update());for(const i of Object.keys(this))"_"!==i[0]&&this._setProp(i,this[i]);for(const i of r.map(D))Object.defineProperty(this,i,{get(){return this._getProp(i)},set(e){this._setProp(i,e)}});this._applyStyles(n)},t=this._def.__asyncLoader;t?t().then(e):e(this._def)}_setAttr(e){let t=this.getAttribute(e);this._numberProps&&this._numberProps[e]&&(t=Y(t)),this._setProp(D(e),t,!1)}_getProp(e){return this._props[e]}_setProp(e,t,n=!0){t!==this._props[e]&&(this._props[e]=t,this._instance&&this._update(),n&&(!0===t?this.setAttribute(z(e),""):"string"==typeof t||"number"==typeof t?this.setAttribute(z(e),t+""):t||this.removeAttribute(z(e))))}_update(){Ni(this._createVNode(),this.shadowRoot)}_createVNode(){const e=Jo(this._def,C({},this._props));return this._instance||(e.ce=e=>{this._instance=e,e.isCE=!0,e.emit=(e,...t)=>{this.dispatchEvent(new CustomEvent(e,{detail:t}))};let t=this;for(;t=t&&(t.parentNode||t.host);)if(t instanceof Os){e.parent=t._instance;break}}),e}_applyStyles(e){e&&e.forEach((e=>{const t=document.createElement("style");t.textContent=e,this.shadowRoot.appendChild(t)}))}}function As(e,t){if(128&e.shapeFlag){const n=e.suspense;e=n.activeBranch,n.pendingBranch&&!n.isHydrating&&n.effects.push((()=>{As(n.activeBranch,t)}))}for(;e.component;)e=e.component.subTree;if(1&e.shapeFlag&&e.el)Fs(e.el,t);else if(e.type===Oo)e.children.forEach((e=>As(e,t)));else if(e.type===Mo){let{el:n,anchor:o}=e;for(;n&&(Fs(n,t),n!==o);)n=n.nextSibling}}function Fs(e,t){if(1===e.nodeType){const n=e.style;for(const e in t)n.setProperty(`--${e}`,t[e])}}const Ms="transition",Ps="animation",Vs=(e,{slots:t})=>cs(sn,Us(e),t);Vs.displayName="Transition";const Is={name:String,type:String,css:{type:Boolean,default:!0},duration:[String,Number,Object],enterFromClass:String,enterActiveClass:String,enterToClass:String,appearFromClass:String,appearActiveClass:String,appearToClass:String,leaveFromClass:String,leaveActiveClass:String,leaveToClass:String},Bs=Vs.props=C({},sn.props,Is),Ls=(e,t=[])=>{N(e)?e.forEach((e=>e(...t))):e&&e(...t)},js=e=>!!e&&(N(e)?e.some((e=>e.length>1)):e.length>1);function Us(e){const t={};for(const C in e)C in Is||(t[C]=e[C]);if(!1===e.css)return t;const{name:n="v",type:o,duration:r,enterFromClass:s=`${n}-enter-from`,enterActiveClass:i=`${n}-enter-active`,enterToClass:l=`${n}-enter-to`,appearFromClass:c=s,appearActiveClass:a=i,appearToClass:u=l,leaveFromClass:p=`${n}-leave-from`,leaveActiveClass:f=`${n}-leave-active`,leaveToClass:d=`${n}-leave-to`}=e,h=function(e){if(null==e)return null;if(M(e))return[Hs(e.enter),Hs(e.leave)];{const t=Hs(e);return[t,t]}}(r),m=h&&h[0],g=h&&h[1],{onBeforeEnter:v,onEnter:y,onEnterCancelled:b,onLeave:_,onLeaveCancelled:S,onBeforeAppear:x=v,onAppear:w=y,onAppearCancelled:k=b}=t,T=(e,t,n)=>{Ws(e,t?u:l),Ws(e,t?a:i),n&&n()},N=(e,t)=>{Ws(e,d),Ws(e,f),t&&t()},E=e=>(t,n)=>{const r=e?w:y,i=()=>T(t,e,n);Ls(r,[t,i]),zs((()=>{Ws(t,e?c:s),Ds(t,e?u:l),js(r)||Gs(t,o,m,i)}))};return C(t,{onBeforeEnter(e){Ls(v,[e]),Ds(e,s),Ds(e,i)},onBeforeAppear(e){Ls(x,[e]),Ds(e,c),Ds(e,a)},onEnter:E(!1),onAppear:E(!0),onLeave(e,t){const n=()=>N(e,t);Ds(e,p),Ys(),Ds(e,f),zs((()=>{Ws(e,p),Ds(e,d),js(_)||Gs(e,o,g,n)})),Ls(_,[e,n])},onEnterCancelled(e){T(e,!1),Ls(b,[e])},onAppearCancelled(e){T(e,!0),Ls(k,[e])},onLeaveCancelled(e){N(e),Ls(S,[e])}})}function Hs(e){return Y(e)}function Ds(e,t){t.split(/\s+/).forEach((t=>t&&e.classList.add(t))),(e._vtc||(e._vtc=new Set)).add(t)}function Ws(e,t){t.split(/\s+/).forEach((t=>t&&e.classList.remove(t)));const{_vtc:n}=e;n&&(n.delete(t),n.size||(e._vtc=void 0))}function zs(e){requestAnimationFrame((()=>{requestAnimationFrame(e)}))}let Ks=0;function Gs(e,t,n,o){const r=e._endId=++Ks,s=()=>{r===e._endId&&o()};if(n)return setTimeout(s,n);const{type:i,timeout:l,propCount:c}=qs(e,t);if(!i)return o();const a=i+"end";let u=0;const p=()=>{e.removeEventListener(a,f),s()},f=t=>{t.target===e&&++u>=c&&p()};setTimeout((()=>{u(n[e]||"").split(", "),r=o("transitionDelay"),s=o("transitionDuration"),i=Js(r,s),l=o("animationDelay"),c=o("animationDuration"),a=Js(l,c);let u=null,p=0,f=0;t===Ms?i>0&&(u=Ms,p=i,f=s.length):t===Ps?a>0&&(u=Ps,p=a,f=c.length):(p=Math.max(i,a),u=p>0?i>a?Ms:Ps:null,f=u?u===Ms?s.length:c.length:0);return{type:u,timeout:p,propCount:f,hasTransform:u===Ms&&/\b(transform|all)(,|$)/.test(n.transitionProperty)}}function Js(e,t){for(;e.lengthZs(t)+Zs(e[n]))))}function Zs(e){return 1e3*Number(e.slice(0,-1).replace(",","."))}function Ys(){return document.body.offsetHeight}const Qs=new WeakMap,Xs=new WeakMap,ei={name:"TransitionGroup",props:C({},Bs,{tag:String,moveClass:String}),setup(e,{slots:t}){const n=pr(),o=on();let r,s;return Rn((()=>{if(!r.length)return;const t=e.moveClass||`${e.name||"v"}-move`;if(!function(e,t,n){const o=e.cloneNode();e._vtc&&e._vtc.forEach((e=>{e.split(/\s+/).forEach((e=>e&&o.classList.remove(e)))}));n.split(/\s+/).forEach((e=>e&&o.classList.add(e))),o.style.display="none";const r=1===t.nodeType?t:t.parentNode;r.appendChild(o);const{hasTransform:s}=qs(o);return r.removeChild(o),s}(r[0].el,n.vnode.el,t))return;r.forEach(ti),r.forEach(ni);const o=r.filter(oi);Ys(),o.forEach((e=>{const n=e.el,o=n.style;Ds(n,t),o.transform=o.webkitTransform=o.transitionDuration="";const r=n._moveCb=e=>{e&&e.target!==n||e&&!/transform$/.test(e.propertyName)||(n.removeEventListener("transitionend",r),n._moveCb=null,Ws(n,t))};n.addEventListener("transitionend",r)}))})),()=>{const i=yt(e),l=Us(i);let c=i.tag||Oo;r=s,s=t.default?fn(t.default()):[];for(let e=0;e{const t=e.props["onUpdate:modelValue"];return N(t)?e=>J(t,e):t};function si(e){e.target.composing=!0}function ii(e){const t=e.target;t.composing&&(t.composing=!1,function(e,t){const n=document.createEvent("HTMLEvents");n.initEvent(t,!0,!0),e.dispatchEvent(n)}(t,"input"))}const li={created(e,{modifiers:{lazy:t,trim:n,number:o}},r){e._assign=ri(r);const s=o||r.props&&"number"===r.props.type;ks(e,t?"change":"input",(t=>{if(t.target.composing)return;let o=e.value;n?o=o.trim():s&&(o=Y(o)),e._assign(o)})),n&&ks(e,"change",(()=>{e.value=e.value.trim()})),t||(ks(e,"compositionstart",si),ks(e,"compositionend",ii),ks(e,"change",ii))},mounted(e,{value:t}){e.value=null==t?"":t},beforeUpdate(e,{value:t,modifiers:{lazy:n,trim:o,number:r}},s){if(e._assign=ri(s),e.composing)return;if(document.activeElement===e){if(n)return;if(o&&e.value.trim()===t)return;if((r||"number"===e.type)&&Y(e.value)===t)return}const i=null==t?"":t;e.value!==i&&(e.value=i)}},ci={deep:!0,created(e,t,n){e._assign=ri(n),ks(e,"change",(()=>{const t=e._modelValue,n=di(e),o=e.checked,r=e._assign;if(N(t)){const e=h(t,n),s=-1!==e;if(o&&!s)r(t.concat(n));else if(!o&&s){const n=[...t];n.splice(e,1),r(n)}}else if($(t)){const e=new Set(t);o?e.add(n):e.delete(n),r(e)}else r(hi(e,o))}))},mounted:ai,beforeUpdate(e,t,n){e._assign=ri(n),ai(e,t,n)}};function ai(e,{value:t,oldValue:n},o){e._modelValue=t,N(t)?e.checked=h(t,o.props.value)>-1:$(t)?e.checked=t.has(o.props.value):t!==n&&(e.checked=d(t,hi(e,!0)))}const ui={created(e,{value:t},n){e.checked=d(t,n.props.value),e._assign=ri(n),ks(e,"change",(()=>{e._assign(di(e))}))},beforeUpdate(e,{value:t,oldValue:n},o){e._assign=ri(o),t!==n&&(e.checked=d(t,o.props.value))}},pi={deep:!0,created(e,{value:t,modifiers:{number:n}},o){const r=$(t);ks(e,"change",(()=>{const t=Array.prototype.filter.call(e.options,(e=>e.selected)).map((e=>n?Y(di(e)):di(e)));e._assign(e.multiple?r?new Set(t):t:t[0])})),e._assign=ri(o)},mounted(e,{value:t}){fi(e,t)},beforeUpdate(e,t,n){e._assign=ri(n)},updated(e,{value:t}){fi(e,t)}};function fi(e,t){const n=e.multiple;if(!n||N(t)||$(t)){for(let o=0,r=e.options.length;o-1:t.has(s);else if(d(di(r),t))return void(e.selectedIndex!==o&&(e.selectedIndex=o))}n||-1===e.selectedIndex||(e.selectedIndex=-1)}}function di(e){return"_value"in e?e._value:e.value}function hi(e,t){const n=t?"_trueValue":"_falseValue";return n in e?e[n]:t}const mi={created(e,t,n){gi(e,t,n,null,"created")},mounted(e,t,n){gi(e,t,n,null,"mounted")},beforeUpdate(e,t,n,o){gi(e,t,n,o,"beforeUpdate")},updated(e,t,n,o){gi(e,t,n,o,"updated")}};function gi(e,t,n,o,r){let s;switch(e.tagName){case"SELECT":s=pi;break;case"TEXTAREA":s=li;break;default:switch(n.props&&n.props.type){case"checkbox":s=ci;break;case"radio":s=ui;break;default:s=li}}const i=s[r];i&&i(e,t,n,o)}const vi=["ctrl","shift","alt","meta"],yi={stop:e=>e.stopPropagation(),prevent:e=>e.preventDefault(),self:e=>e.target!==e.currentTarget,ctrl:e=>!e.ctrlKey,shift:e=>!e.shiftKey,alt:e=>!e.altKey,meta:e=>!e.metaKey,left:e=>"button"in e&&0!==e.button,middle:e=>"button"in e&&1!==e.button,right:e=>"button"in e&&2!==e.button,exact:(e,t)=>vi.some((n=>e[`${n}Key`]&&!t.includes(n)))},bi={esc:"escape",space:" ",up:"arrow-up",left:"arrow-left",right:"arrow-right",down:"arrow-down",delete:"backspace"},_i={beforeMount(e,{value:t},{transition:n}){e._vod="none"===e.style.display?"":e.style.display,n&&t?n.beforeEnter(e):Si(e,t)},mounted(e,{value:t},{transition:n}){n&&t&&n.enter(e)},updated(e,{value:t,oldValue:n},{transition:o}){!t!=!n&&(o?t?(o.beforeEnter(e),Si(e,!0),o.enter(e)):o.leave(e,(()=>{Si(e,!1)})):Si(e,t))},beforeUnmount(e,{value:t}){Si(e,t)}};function Si(e,t){e.style.display=t?e._vod:"none"}const xi=C({patchProp:(e,t,n,s,i=!1,l,c,a,u)=>{"class"===t?function(e,t,n){const o=e._vtc;o&&(t=(t?[t,...o]:[...o]).join(" ")),null==t?e.removeAttribute("class"):n?e.setAttribute("class",t):e.className=t}(e,s,i):"style"===t?function(e,t,n){const o=e.style,r=o.display;if(n)if(A(n))t!==n&&(o.cssText=n);else{for(const e in n)gs(o,e,n[e]);if(t&&!A(t))for(const e in t)null==n[e]&&gs(o,e,"")}else e.removeAttribute("style");"_vod"in e&&(o.display=r)}(e,n,s):S(t)?x(t)||Ts(e,t,0,s,c):("."===t[0]?(t=t.slice(1),1):"^"===t[0]?(t=t.slice(1),0):function(e,t,n,o){if(o)return"innerHTML"===t||"textContent"===t||!!(t in e&&Es.test(t)&&O(n));if("spellcheck"===t||"draggable"===t)return!1;if("form"===t)return!1;if("list"===t&&"INPUT"===e.tagName)return!1;if("type"===t&&"TEXTAREA"===e.tagName)return!1;if(Es.test(t)&&A(n))return!1;return t in e}(e,t,s,i))?function(e,t,n,o,s,i,l){if("innerHTML"===t||"textContent"===t)return o&&l(o,s,i),void(e[t]=null==n?"":n);if("value"===t&&"PROGRESS"!==e.tagName){e._value=n;const o=null==n?"":n;return e.value!==o&&(e.value=o),void(null==n&&e.removeAttribute(t))}if(""===n||null==n){const o=typeof e[t];if("boolean"===o)return void(e[t]=r(n));if(null==n&&"string"===o)return e[t]="",void e.removeAttribute(t);if("number"===o){try{e[t]=0}catch(c){}return void e.removeAttribute(t)}}try{e[t]=n}catch(a){}}(e,t,s,l,c,a,u):("true-value"===t?e._trueValue=s:"false-value"===t&&(e._falseValue=s),function(e,t,n,s,i){if(s&&t.startsWith("xlink:"))null==n?e.removeAttributeNS(bs,t.slice(6,t.length)):e.setAttributeNS(bs,t,n);else{const s=o(t);null==n||s&&!r(n)?e.removeAttribute(t):e.setAttribute(t,s?"":n)}}(e,t,s,i))}},hs);let Ci,wi=!1;function ki(){return Ci||(Ci=go(xi))}function Ti(){return Ci=wi?Ci:vo(xi),wi=!0,Ci}const Ni=(...e)=>{ki().render(...e)},Ei=(...e)=>{Ti().hydrate(...e)};function $i(e){if(A(e)){return document.querySelector(e)}return e}const Ri=y;function Oi(e){throw e}function Ai(e){}function Fi(e,t,n,o){const r=new SyntaxError(String(e));return r.code=e,r.loc=t,r}const Mi=Symbol(""),Pi=Symbol(""),Vi=Symbol(""),Ii=Symbol(""),Bi=Symbol(""),Li=Symbol(""),ji=Symbol(""),Ui=Symbol(""),Hi=Symbol(""),Di=Symbol(""),Wi=Symbol(""),zi=Symbol(""),Ki=Symbol(""),Gi=Symbol(""),qi=Symbol(""),Ji=Symbol(""),Zi=Symbol(""),Yi=Symbol(""),Qi=Symbol(""),Xi=Symbol(""),el=Symbol(""),tl=Symbol(""),nl=Symbol(""),ol=Symbol(""),rl=Symbol(""),sl=Symbol(""),il=Symbol(""),ll=Symbol(""),cl=Symbol(""),al=Symbol(""),ul=Symbol(""),pl=Symbol(""),fl=Symbol(""),dl=Symbol(""),hl=Symbol(""),ml=Symbol(""),gl=Symbol(""),vl=Symbol(""),yl=Symbol(""),bl={[Mi]:"Fragment",[Pi]:"Teleport",[Vi]:"Suspense",[Ii]:"KeepAlive",[Bi]:"BaseTransition",[Li]:"openBlock",[ji]:"createBlock",[Ui]:"createElementBlock",[Hi]:"createVNode",[Di]:"createElementVNode",[Wi]:"createCommentVNode",[zi]:"createTextVNode",[Ki]:"createStaticVNode",[Gi]:"resolveComponent",[qi]:"resolveDynamicComponent",[Ji]:"resolveDirective",[Zi]:"resolveFilter",[Yi]:"withDirectives",[Qi]:"renderList",[Xi]:"renderSlot",[el]:"createSlots",[tl]:"toDisplayString",[nl]:"mergeProps",[ol]:"normalizeClass",[rl]:"normalizeStyle",[sl]:"normalizeProps",[il]:"guardReactiveProps",[ll]:"toHandlers",[cl]:"camelize",[al]:"capitalize",[ul]:"toHandlerKey",[pl]:"setBlockTracking",[fl]:"pushScopeId",[dl]:"popScopeId",[hl]:"withCtx",[ml]:"unref",[gl]:"isRef",[vl]:"withMemo",[yl]:"isMemoSame"};const _l={source:"",start:{line:1,column:1,offset:0},end:{line:1,column:1,offset:0}};function Sl(e,t,n,o,r,s,i,l=!1,c=!1,a=!1,u=_l){return e&&(l?(e.helper(Li),e.helper(Zl(e.inSSR,a))):e.helper(Jl(e.inSSR,a)),i&&e.helper(Yi)),{type:13,tag:t,props:n,children:o,patchFlag:r,dynamicProps:s,directives:i,isBlock:l,disableTracking:c,isComponent:a,loc:u}}function xl(e,t=_l){return{type:17,loc:t,elements:e}}function Cl(e,t=_l){return{type:15,loc:t,properties:e}}function wl(e,t){return{type:16,loc:_l,key:A(e)?kl(e,!0):e,value:t}}function kl(e,t=!1,n=_l,o=0){return{type:4,loc:n,content:e,isStatic:t,constType:t?3:o}}function Tl(e,t=_l){return{type:8,loc:t,children:e}}function Nl(e,t=[],n=_l){return{type:14,loc:n,callee:e,arguments:t}}function El(e,t,n=!1,o=!1,r=_l){return{type:18,params:e,returns:t,newline:n,isSlot:o,loc:r}}function $l(e,t,n,o=!0){return{type:19,test:e,consequent:t,alternate:n,newline:o,loc:_l}}const Rl=e=>4===e.type&&e.isStatic,Ol=(e,t)=>e===t||e===z(t);function Al(e){return Ol(e,"Teleport")?Pi:Ol(e,"Suspense")?Vi:Ol(e,"KeepAlive")?Ii:Ol(e,"BaseTransition")?Bi:void 0}const Fl=/^\d|[^\$\w]/,Ml=e=>!Fl.test(e),Pl=/[A-Za-z_$\xA0-\uFFFF]/,Vl=/[\.\?\w$\xA0-\uFFFF]/,Il=/\s+[.[]\s*|\s*[.[]\s+/g,Bl=e=>{e=e.trim().replace(Il,(e=>e.trim()));let t=0,n=[],o=0,r=0,s=null;for(let i=0;i4===e.key.type&&e.key.content===n))}e||s.properties.unshift(t),o=s}else o=Nl(n.helper(nl),[Cl([t]),s]),r&&r.callee===il&&(r=i[i.length-2]);13===e.type?r?r.arguments[0]=o:e.props=o:r?r.arguments[0]=o:e.arguments[2]=o}function ec(e,t){return`_${t}_${e.replace(/[^\w]/g,((t,n)=>"-"===t?"_":e.charCodeAt(n).toString()))}`}function tc(e,{helper:t,removeHelper:n,inSSR:o}){e.isBlock||(e.isBlock=!0,n(Jl(o,e.isComponent)),t(Li),t(Zl(o,e.isComponent)))}const nc=/&(gt|lt|amp|apos|quot);/g,oc={gt:">",lt:"<",amp:"&",apos:"'",quot:'"'},rc={delimiters:["{{","}}"],getNamespace:()=>0,getTextMode:()=>0,isVoidTag:b,isPreTag:b,isCustomElement:b,decodeEntities:e=>e.replace(nc,((e,t)=>oc[t])),onError:Oi,onWarn:Ai,comments:!1};function sc(e,t={}){const n=function(e,t){const n=C({},rc);let o;for(o in t)n[o]=void 0===t[o]?rc[o]:t[o];return{options:n,column:1,line:1,offset:0,originalSource:e,source:e,inPre:!1,inVPre:!1,onWarn:n.onWarn}}(e,t),o=bc(n);return function(e,t=_l){return{type:0,children:e,helpers:[],components:[],directives:[],hoists:[],imports:[],cached:0,temps:0,codegenNode:void 0,loc:t}}(ic(n,0,[]),_c(n,o))}function ic(e,t,n){const o=Sc(n),r=o?o.ns:0,s=[];for(;!Tc(e,t,n);){const i=e.source;let l;if(0===t||1===t)if(!e.inVPre&&xc(i,e.options.delimiters[0]))l=gc(e,t);else if(0===t&&"<"===i[0])if(1===i.length);else if("!"===i[1])l=xc(i,"\x3c!--")?ac(e):xc(i,""===i[2]){Cc(e,3);continue}if(/[a-z]/i.test(i[2])){dc(e,1,o);continue}l=uc(e)}else/[a-z]/i.test(i[1])?l=pc(e,n):"?"===i[1]&&(l=uc(e));if(l||(l=vc(e,t)),N(l))for(let e=0;e/.exec(e.source);if(o){n=e.source.slice(4,o.index);const t=e.source.slice(0,o.index);let r=1,s=0;for(;-1!==(s=t.indexOf("\x3c!--",r));)Cc(e,s-r+1),r=s+1;Cc(e,o.index+o[0].length-r+1)}else n=e.source.slice(4),Cc(e,e.source.length);return{type:3,content:n,loc:_c(e,t)}}function uc(e){const t=bc(e),n="?"===e.source[1]?1:2;let o;const r=e.source.indexOf(">");return-1===r?(o=e.source.slice(n),Cc(e,e.source.length)):(o=e.source.slice(n,r),Cc(e,r+1)),{type:3,content:o,loc:_c(e,t)}}function pc(e,t){const n=e.inPre,o=e.inVPre,r=Sc(t),s=dc(e,0,r),i=e.inPre&&!n,l=e.inVPre&&!o;if(s.isSelfClosing||e.options.isVoidTag(s.tag))return i&&(e.inPre=!1),l&&(e.inVPre=!1),s;t.push(s);const c=e.options.getTextMode(s,r),a=ic(e,c,t);if(t.pop(),s.children=a,Nc(e.source,s.tag))dc(e,1,r);else if(0===e.source.length&&"script"===s.tag.toLowerCase()){const e=a[0];e&&xc(e.loc.source,"\x3c!--")}return s.loc=_c(e,s.loc.start),i&&(e.inPre=!1),l&&(e.inVPre=!1),s}const fc=t("if,else,else-if,for,slot");function dc(e,t,n){const o=bc(e),r=/^<\/?([a-z][^\t\r\n\f />]*)/i.exec(e.source),s=r[1],i=e.options.getNamespace(s,n);Cc(e,r[0].length),wc(e);const l=bc(e),c=e.source;e.options.isPreTag(s)&&(e.inPre=!0);let a=hc(e,t);0===t&&!e.inVPre&&a.some((e=>7===e.type&&"pre"===e.name))&&(e.inVPre=!0,C(e,l),e.source=c,a=hc(e,t).filter((e=>"v-pre"!==e.name)));let u=!1;if(0===e.source.length||(u=xc(e.source,"/>"),Cc(e,u?2:1)),1===t)return;let p=0;return e.inVPre||("slot"===s?p=2:"template"===s?a.some((e=>7===e.type&&fc(e.name)))&&(p=3):function(e,t,n){const o=n.options;if(o.isCustomElement(e))return!1;if("component"===e||/^[A-Z]/.test(e)||Al(e)||o.isBuiltInComponent&&o.isBuiltInComponent(e)||o.isNativeTag&&!o.isNativeTag(e))return!0;for(let r=0;r0&&!xc(e.source,">")&&!xc(e.source,"/>");){if(xc(e.source,"/")){Cc(e,1),wc(e);continue}const r=mc(e,o);6===r.type&&r.value&&"class"===r.name&&(r.value.content=r.value.content.replace(/\s+/g," ").trim()),0===t&&n.push(r),/^[^\t\r\n\f />]/.test(e.source),wc(e)}return n}function mc(e,t){const n=bc(e),o=/^[^\t\r\n\f />][^\t\r\n\f />=]*/.exec(e.source)[0];t.has(o),t.add(o);{const e=/["'<]/g;let t;for(;t=e.exec(o););}let r;Cc(e,o.length),/^[\t\r\n\f ]*=/.test(e.source)&&(wc(e),Cc(e,1),wc(e),r=function(e){const t=bc(e);let n;const o=e.source[0],r='"'===o||"'"===o;if(r){Cc(e,1);const t=e.source.indexOf(o);-1===t?n=yc(e,e.source.length,4):(n=yc(e,t,4),Cc(e,1))}else{const t=/^[^\t\r\n\f >]+/.exec(e.source);if(!t)return;const o=/["'<=`]/g;let r;for(;r=o.exec(t[0]););n=yc(e,t[0].length,4)}return{content:n,isQuoted:r,loc:_c(e,t)}}(e));const s=_c(e,n);if(!e.inVPre&&/^(v-[A-Za-z0-9-]|:|\.|@|#)/.test(o)){const t=/(?:^v-([a-z0-9-]+))?(?:(?::|^\.|^@|^#)(\[[^\]]+\]|[^\.]+))?(.+)?$/i.exec(o);let i,l=xc(o,"."),c=t[1]||(l||xc(o,":")?"bind":xc(o,"@")?"on":"slot");if(t[2]){const r="slot"===c,s=o.lastIndexOf(t[2]),l=_c(e,kc(e,n,s),kc(e,n,s+t[2].length+(r&&t[3]||"").length));let a=t[2],u=!0;a.startsWith("[")?(u=!1,a=a.endsWith("]")?a.substr(1,a.length-2):a.substr(1)):r&&(a+=t[3]||""),i={type:4,content:a,isStatic:u,constType:u?3:0,loc:l}}if(r&&r.isQuoted){const e=r.loc;e.start.offset++,e.start.column++,e.end=jl(e.start,r.content),e.source=e.source.slice(1,-1)}const a=t[3]?t[3].substr(1).split("."):[];return l&&a.push("prop"),{type:7,name:c,exp:r&&{type:4,content:r.content,isStatic:!1,constType:0,loc:r.loc},arg:i,modifiers:a,loc:s}}return!e.inVPre&&xc(o,"v-"),{type:6,name:o,value:r&&{type:2,content:r.content,loc:r.loc},loc:s}}function gc(e,t){const[n,o]=e.options.delimiters,r=e.source.indexOf(o,n.length);if(-1===r)return;const s=bc(e);Cc(e,n.length);const i=bc(e),l=bc(e),c=r-n.length,a=e.source.slice(0,c),u=yc(e,c,t),p=u.trim(),f=u.indexOf(p);f>0&&Ul(i,a,f);return Ul(l,a,c-(u.length-p.length-f)),Cc(e,o.length),{type:5,content:{type:4,isStatic:!1,constType:0,content:p,loc:_c(e,i,l)},loc:_c(e,s)}}function vc(e,t){const n=3===t?["]]>"]:["<",e.options.delimiters[0]];let o=e.source.length;for(let s=0;st&&(o=t)}const r=bc(e);return{type:2,content:yc(e,o,t),loc:_c(e,r)}}function yc(e,t,n){const o=e.source.slice(0,t);return Cc(e,t),2===n||3===n||-1===o.indexOf("&")?o:e.options.decodeEntities(o,4===n)}function bc(e){const{column:t,line:n,offset:o}=e;return{column:t,line:n,offset:o}}function _c(e,t,n){return{start:t,end:n=n||bc(e),source:e.originalSource.slice(t.offset,n.offset)}}function Sc(e){return e[e.length-1]}function xc(e,t){return e.startsWith(t)}function Cc(e,t){const{source:n}=e;Ul(e,n,t),e.source=n.slice(t)}function wc(e){const t=/^[\t\r\n\f ]+/.exec(e.source);t&&Cc(e,t[0].length)}function kc(e,t,n){return jl(t,e.originalSource.slice(t.offset,n),n)}function Tc(e,t,n){const o=e.source;switch(t){case 0:if(xc(o,"=0;--e)if(Nc(o,n[e].tag))return!0;break;case 1:case 2:{const e=Sc(n);if(e&&Nc(o,e.tag))return!0;break}case 3:if(xc(o,"]]>"))return!0}return!o}function Nc(e,t){return xc(e,"]/.test(e[2+t.length]||">")}function Ec(e,t){Rc(e,t,$c(e,e.children[0]))}function $c(e,t){const{children:n}=e;return 1===n.length&&1===t.type&&!ql(t)}function Rc(e,t,n=!1){let o=!0;const{children:r}=e,s=r.length;let i=0;for(let l=0;l0){if(r<3&&(o=!1),r>=2){e.codegenNode.patchFlag="-1",e.codegenNode=t.hoist(e.codegenNode),i++;continue}}else{const n=e.codegenNode;if(13===n.type){const o=Vc(n);if((!o||512===o||1===o)&&Mc(e,t)>=2){const o=Pc(e);o&&(n.props=t.hoist(o))}n.dynamicProps&&(n.dynamicProps=t.hoist(n.dynamicProps))}}}else if(12===e.type){const n=Oc(e.content,t);n>0&&(n<3&&(o=!1),n>=2&&(e.codegenNode=t.hoist(e.codegenNode),i++))}if(1===e.type){const n=1===e.tagType;n&&t.scopes.vSlot++,Rc(e,t),n&&t.scopes.vSlot--}else if(11===e.type)Rc(e,t,1===e.children.length);else if(9===e.type)for(let n=0;n1)for(let r=0;r`_${bl[k.helper(e)]}`,replaceNode(e){k.parent.children[k.childIndex]=k.currentNode=e},removeNode(e){const t=e?k.parent.children.indexOf(e):k.currentNode?k.childIndex:-1;e&&e!==k.currentNode?k.childIndex>t&&(k.childIndex--,k.onNodeRemoved()):(k.currentNode=null,k.onNodeRemoved()),k.parent.children.splice(t,1)},onNodeRemoved:()=>{},addIdentifiers(e){},removeIdentifiers(e){},hoist(e){A(e)&&(e=kl(e)),k.hoists.push(e);const t=kl(`_hoisted_${k.hoists.length}`,!1,e.loc,2);return t.hoisted=e,t},cache:(e,t=!1)=>function(e,t,n=!1){return{type:20,index:e,value:t,isVNode:n,loc:_l}}(k.cached++,e,t)};return k}function Bc(e,t){const n=Ic(e,t);Lc(e,n),t.hoistStatic&&Ec(e,n),t.ssr||function(e,t){const{helper:n}=t,{children:o}=e;if(1===o.length){const n=o[0];if($c(e,n)&&n.codegenNode){const o=n.codegenNode;13===o.type&&tc(o,t),e.codegenNode=o}else e.codegenNode=n}else if(o.length>1){let o=64;e.codegenNode=Sl(t,n(Mi),void 0,e.children,o+"",void 0,void 0,!0,void 0,!1)}}(e,n),e.helpers=[...n.helpers.keys()],e.components=[...n.components],e.directives=[...n.directives],e.imports=n.imports,e.hoists=n.hoists,e.temps=n.temps,e.cached=n.cached}function Lc(e,t){t.currentNode=e;const{nodeTransforms:n}=t,o=[];for(let s=0;s{n--};for(;nt===e:t=>e.test(t);return(e,o)=>{if(1===e.type){const{props:r}=e;if(3===e.tagType&&r.some(Kl))return;const s=[];for(let i=0;i`_${bl[e]}`,push(e,t){d.code+=e},indent(){h(++d.indentLevel)},deindent(e=!1){e?--d.indentLevel:h(--d.indentLevel)},newline(){h(d.indentLevel)}};function h(e){d.push("\n"+" ".repeat(e))}return d}(e,t);t.onContextCreated&&t.onContextCreated(n);const{mode:o,push:r,prefixIdentifiers:s,indent:i,deindent:l,newline:c,ssr:a}=n,u=e.helpers.length>0,p=!s&&"module"!==o;!function(e,t){const{push:n,newline:o,runtimeGlobalName:r}=t,s=r,i=e=>`${bl[e]}: _${bl[e]}`;if(e.helpers.length>0&&(n(`const _Vue = ${s}\n`),e.hoists.length)){n(`const { ${[Hi,Di,Wi,zi,Ki].filter((t=>e.helpers.includes(t))).map(i).join(", ")} } = _Vue\n`)}(function(e,t){if(!e.length)return;t.pure=!0;const{push:n,newline:o}=t;o();for(let r=0;r`${bl[e]}: _${bl[e]}`)).join(", ")} } = _Vue`),r("\n"),c())),e.components.length&&(Dc(e.components,"component",n),(e.directives.length||e.temps>0)&&c()),e.directives.length&&(Dc(e.directives,"directive",n),e.temps>0&&c()),e.temps>0){r("let ");for(let t=0;t0?", ":""}_temp${t}`)}return(e.components.length||e.directives.length||e.temps)&&(r("\n"),c()),a||r("return "),e.codegenNode?Kc(e.codegenNode,n):r("null"),p&&(l(),r("}")),l(),r("}"),{ast:e,code:n.code,preamble:"",map:n.map?n.map.toJSON():void 0}}function Dc(e,t,{helper:n,push:o,newline:r,isTS:s}){const i=n("component"===t?Gi:Ji);for(let l=0;l3||!1;t.push("["),n&&t.indent(),zc(e,t,n),n&&t.deindent(),t.push("]")}function zc(e,t,n=!1,o=!0){const{push:r,newline:s}=t;for(let i=0;ie||"null"))}([s,i,l,c,a]),t),n(")"),p&&n(")");u&&(n(", "),Kc(u,t),n(")"))}(e,t);break;case 14:!function(e,t){const{push:n,helper:o,pure:r}=t,s=A(e.callee)?e.callee:o(e.callee);r&&n(Uc);n(s+"(",e),zc(e.arguments,t),n(")")}(e,t);break;case 15:!function(e,t){const{push:n,indent:o,deindent:r,newline:s}=t,{properties:i}=e;if(!i.length)return void n("{}",e);const l=i.length>1||!1;n(l?"{":"{ "),l&&o();for(let c=0;c "),(c||l)&&(n("{"),o());i?(c&&n("return "),N(i)?Wc(i,t):Kc(i,t)):l&&Kc(l,t);(c||l)&&(r(),n("}"));a&&n(")")}(e,t);break;case 19:!function(e,t){const{test:n,consequent:o,alternate:r,newline:s}=e,{push:i,indent:l,deindent:c,newline:a}=t;if(4===n.type){const e=!Ml(n.content);e&&i("("),Gc(n,t),e&&i(")")}else i("("),Kc(n,t),i(")");s&&l(),t.indentLevel++,s||i(" "),i("? "),Kc(o,t),t.indentLevel--,s&&a(),s||i(" "),i(": ");const u=19===r.type;u||t.indentLevel++;Kc(r,t),u||t.indentLevel--;s&&c(!0)}(e,t);break;case 20:!function(e,t){const{push:n,helper:o,indent:r,deindent:s,newline:i}=t;n(`_cache[${e.index}] || (`),e.isVNode&&(r(),n(`${o(pl)}(-1),`),i());n(`_cache[${e.index}] = `),Kc(e.value,t),e.isVNode&&(n(","),i(),n(`${o(pl)}(1),`),i(),n(`_cache[${e.index}]`),s());n(")")}(e,t);break;case 21:zc(e.body,t,!0,!1)}}function Gc(e,t){const{content:n,isStatic:o}=e;t.push(o?JSON.stringify(n):n,e)}function qc(e,t){for(let n=0;nfunction(e,t,n,o){if(!("else"===t.name||t.exp&&t.exp.content.trim())){t.exp=kl("true",!1,t.exp?t.exp.loc:e.loc)}if("if"===t.name){const r=Yc(e,t),s={type:9,loc:e.loc,branches:[r]};if(n.replaceNode(s),o)return o(s,r,!0)}else{const r=n.parent.children;let s=r.indexOf(e);for(;s-- >=-1;){const i=r[s];if(!i||2!==i.type||i.content.trim().length){if(i&&9===i.type){n.removeNode();const r=Yc(e,t);i.branches.push(r);const s=o&&o(i,r,!1);Lc(r,n),s&&s(),n.currentNode=null}break}n.removeNode(i)}}}(e,t,n,((e,t,o)=>{const r=n.parent.children;let s=r.indexOf(e),i=0;for(;s-- >=0;){const e=r[s];e&&9===e.type&&(i+=e.branches.length)}return()=>{if(o)e.codegenNode=Qc(t,i,n);else{(function(e){for(;;)if(19===e.type){if(19!==e.alternate.type)return e;e=e.alternate}else 20===e.type&&(e=e.value)}(e.codegenNode)).alternate=Qc(t,i+e.branches.length-1,n)}}}))));function Yc(e,t){return{type:10,loc:e.loc,condition:"else"===t.name?void 0:t.exp,children:3!==e.tagType||Hl(e,"for")?[e]:e.children,userKey:Dl(e,"key")}}function Qc(e,t,n){return e.condition?$l(e.condition,Xc(e,t,n),Nl(n.helper(Wi),['""',"true"])):Xc(e,t,n)}function Xc(e,t,n){const{helper:o}=n,r=wl("key",kl(`${t}`,!1,_l,2)),{children:s}=e,i=s[0];if(1!==s.length||1!==i.type){if(1===s.length&&11===i.type){const e=i.codegenNode;return Xl(e,r,n),e}{let t=64;return Sl(n,o(Mi),Cl([r]),s,t+"",void 0,void 0,!0,!1,!1,e.loc)}}{const e=i.codegenNode,t=14===(l=e).type&&l.callee===vl?l.arguments[1].returns:l;return 13===t.type&&tc(t,n),Xl(t,r,n),e}var l}const ea=jc("for",((e,t,n)=>{const{helper:o,removeHelper:r}=n;return function(e,t,n,o){if(!t.exp)return;const r=ra(t.exp);if(!r)return;const{scopes:s}=n,{source:i,value:l,key:c,index:a}=r,u={type:11,loc:t.loc,source:i,valueAlias:l,keyAlias:c,objectIndexAlias:a,parseResult:r,children:Gl(e)?e.children:[e]};n.replaceNode(u),s.vFor++;const p=o&&o(u);return()=>{s.vFor--,p&&p()}}(e,t,n,(t=>{const s=Nl(o(Qi),[t.source]),i=Hl(e,"memo"),l=Dl(e,"key"),c=l&&(6===l.type?kl(l.value.content,!0):l.exp),a=l?wl("key",c):null,u=4===t.source.type&&t.source.constType>0,p=u?64:l?128:256;return t.codegenNode=Sl(n,o(Mi),void 0,s,p+"",void 0,void 0,!0,!u,!1,e.loc),()=>{let l;const p=Gl(e),{children:f}=t,d=1!==f.length||1!==f[0].type,h=ql(e)?e:p&&1===e.children.length&&ql(e.children[0])?e.children[0]:null;if(h?(l=h.codegenNode,p&&a&&Xl(l,a,n)):d?l=Sl(n,o(Mi),a?Cl([a]):void 0,e.children,"64",void 0,void 0,!0,void 0,!1):(l=f[0].codegenNode,p&&a&&Xl(l,a,n),l.isBlock!==!u&&(l.isBlock?(r(Li),r(Zl(n.inSSR,l.isComponent))):r(Jl(n.inSSR,l.isComponent))),l.isBlock=!u,l.isBlock?(o(Li),o(Zl(n.inSSR,l.isComponent))):o(Jl(n.inSSR,l.isComponent))),i){const e=El(ia(t.parseResult,[kl("_cached")]));e.body={type:21,body:[Tl(["const _memo = (",i.exp,")"]),Tl(["if (_cached",...c?[" && _cached.key === ",c]:[],` && ${n.helperString(yl)}(_cached, _memo)) return _cached`]),Tl(["const _item = ",l]),kl("_item.memo = _memo"),kl("return _item")],loc:_l},s.arguments.push(e,kl("_cache"),kl(String(n.cached++)))}else s.arguments.push(El(ia(t.parseResult),l,!0))}}))}));const ta=/([\s\S]*?)\s+(?:in|of)\s+([\s\S]*)/,na=/,([^,\}\]]*)(?:,([^,\}\]]*))?$/,oa=/^\(|\)$/g;function ra(e,t){const n=e.loc,o=e.content,r=o.match(ta);if(!r)return;const[,s,i]=r,l={source:sa(n,i.trim(),o.indexOf(i,s.length)),value:void 0,key:void 0,index:void 0};let c=s.trim().replace(oa,"").trim();const a=s.indexOf(c),u=c.match(na);if(u){c=c.replace(na,"").trim();const e=u[1].trim();let t;if(e&&(t=o.indexOf(e,a+c.length),l.key=sa(n,e,t)),u[2]){const r=u[2].trim();r&&(l.index=sa(n,r,o.indexOf(r,l.key?t+e.length:a+c.length)))}}return c&&(l.value=sa(n,c,a)),l}function sa(e,t,n){return kl(t,!1,Ll(e,n,t.length))}function ia({value:e,key:t,index:n},o=[]){return function(e){let t=e.length;for(;t--&&!e[t];);return e.slice(0,t+1).map(((e,t)=>e||kl("_".repeat(t+1),!1)))}([e,t,n,...o])}const la=kl("undefined",!1),ca=(e,t)=>{if(1===e.type&&(1===e.tagType||3===e.tagType)){const n=Hl(e,"slot");if(n)return t.scopes.vSlot++,()=>{t.scopes.vSlot--}}},aa=(e,t,n)=>El(e,t,!1,!0,t.length?t[0].loc:n);function ua(e,t,n=aa){t.helper(hl);const{children:o,loc:r}=e,s=[],i=[];let l=t.scopes.vSlot>0||t.scopes.vFor>0;const c=Hl(e,"slot",!0);if(c){const{arg:e,exp:t}=c;e&&!Rl(e)&&(l=!0),s.push(wl(e||kl("default",!0),n(t,o,r)))}let a=!1,u=!1;const p=[],f=new Set;for(let m=0;mwl("default",n(e,t,r));a?p.length&&p.some((e=>da(e)))&&(u||s.push(e(void 0,p))):s.push(e(void 0,o))}const d=l?2:fa(e.children)?3:1;let h=Cl(s.concat(wl("_",kl(d+"",!1))),r);return i.length&&(h=Nl(t.helper(el),[h,xl(i)])),{slots:h,hasDynamicSlots:l}}function pa(e,t){return Cl([wl("name",e),wl("fn",t)])}function fa(e){for(let t=0;tfunction(){if(1!==(e=t.currentNode).type||0!==e.tagType&&1!==e.tagType)return;const{tag:n,props:o}=e,r=1===e.tagType;let s=r?function(e,t,n=!1){let{tag:o}=e;const r=ba(o),s=Dl(e,"is");if(s)if(r){const e=6===s.type?s.value&&kl(s.value.content,!0):s.exp;if(e)return Nl(t.helper(qi),[e])}else 6===s.type&&s.value.content.startsWith("vue:")&&(o=s.value.content.slice(4));const i=!r&&Hl(e,"is");if(i&&i.exp)return Nl(t.helper(qi),[i.exp]);const l=Al(o)||t.isBuiltInComponent(o);if(l)return n||t.helper(l),l;return t.helper(Gi),t.components.add(o),ec(o,"component")}(e,t):`"${n}"`;let i,l,c,a,u,p,f=0,d=M(s)&&s.callee===qi||s===Pi||s===Vi||!r&&("svg"===n||"foreignObject"===n||Dl(e,"key",!0));if(o.length>0){const n=ga(e,t);i=n.props,f=n.patchFlag,u=n.dynamicPropNames;const o=n.directives;p=o&&o.length?xl(o.map((e=>function(e,t){const n=[],o=ha.get(e);o?n.push(t.helperString(o)):(t.helper(Ji),t.directives.add(e.name),n.push(ec(e.name,"directive")));const{loc:r}=e;e.exp&&n.push(e.exp);e.arg&&(e.exp||n.push("void 0"),n.push(e.arg));if(Object.keys(e.modifiers).length){e.arg||(e.exp||n.push("void 0"),n.push("void 0"));const t=kl("true",!1,r);n.push(Cl(e.modifiers.map((e=>wl(e,t))),r))}return xl(n,e.loc)}(e,t)))):void 0}if(e.children.length>0){s===Ii&&(d=!0,f|=1024);if(r&&s!==Pi&&s!==Ii){const{slots:n,hasDynamicSlots:o}=ua(e,t);l=n,o&&(f|=1024)}else if(1===e.children.length&&s!==Pi){const n=e.children[0],o=n.type,r=5===o||8===o;r&&0===Oc(n,t)&&(f|=1),l=r||2===o?n:e.children}else l=e.children}0!==f&&(c=String(f),u&&u.length&&(a=function(e){let t="[";for(let n=0,o=e.length;n{if(Rl(e)){const o=e.content,r=S(o);if(i||!r||"onclick"===o.toLowerCase()||"onUpdate:modelValue"===o||j(o)||(h=!0),r&&j(o)&&(g=!0),20===n.type||(4===n.type||8===n.type)&&Oc(n,t)>0)return;"ref"===o?p=!0:"class"===o?f=!0:"style"===o?d=!0:"key"===o||v.includes(o)||v.push(o),!i||"class"!==o&&"style"!==o||v.includes(o)||v.push(o)}else m=!0};for(let _=0;_1?Nl(t.helper(nl),c,s):c[0]):l.length&&(b=Cl(va(l),s)),m?u|=16:(f&&!i&&(u|=2),d&&!i&&(u|=4),v.length&&(u|=8),h&&(u|=32)),0!==u&&32!==u||!(p||g||a.length>0)||(u|=512),!t.inSSR&&b)switch(b.type){case 15:let e=-1,n=-1,o=!1;for(let t=0;t{if(ql(e)){const{children:n,loc:o}=e,{slotName:r,slotProps:s}=function(e,t){let n,o='"default"';const r=[];for(let s=0;s0){const{props:o,directives:s}=ga(e,t,r);n=o}return{slotName:o,slotProps:n}}(e,t),i=[t.prefixIdentifiers?"_ctx.$slots":"$slots",r,"{}","undefined","true"];let l=2;s&&(i[2]=s,l=3),n.length&&(i[3]=El([],n,!1,!1,o),l=4),t.scopeId&&!t.slotted&&(l=5),i.splice(l),e.codegenNode=Nl(t.helper(Xi),i,o)}};const Sa=/^\s*([\w$_]+|(async\s*)?\([^)]*?\))\s*=>|^\s*(async\s+)?function(?:\s+[\w$]+)?\s*\(/,xa=(e,t,n,o)=>{const{loc:r,modifiers:s,arg:i}=e;let l;if(4===i.type)if(i.isStatic){l=kl(G(D(i.content)),!0,i.loc)}else l=Tl([`${n.helperString(ul)}(`,i,")"]);else l=i,l.children.unshift(`${n.helperString(ul)}(`),l.children.push(")");let c=e.exp;c&&!c.content.trim()&&(c=void 0);let a=n.cacheHandlers&&!c&&!n.inVOnce;if(c){const e=Bl(c.content),t=!(e||Sa.test(c.content)),n=c.content.includes(";");(t||a&&e)&&(c=Tl([`${t?"$event":"(...args)"} => ${n?"{":"("}`,c,n?"}":")"]))}let u={props:[wl(l,c||kl("() => {}",!1,r))]};return o&&(u=o(u)),a&&(u.props[0].value=n.cache(u.props[0].value)),u.props.forEach((e=>e.key.isHandlerKey=!0)),u},Ca=(e,t,n)=>{const{exp:o,modifiers:r,loc:s}=e,i=e.arg;return 4!==i.type?(i.children.unshift("("),i.children.push(') || ""')):i.isStatic||(i.content=`${i.content} || ""`),r.includes("camel")&&(4===i.type?i.content=i.isStatic?D(i.content):`${n.helperString(cl)}(${i.content})`:(i.children.unshift(`${n.helperString(cl)}(`),i.children.push(")"))),n.inSSR||(r.includes("prop")&&wa(i,"."),r.includes("attr")&&wa(i,"^")),!o||4===o.type&&!o.content.trim()?{props:[wl(i,kl("",!0,s))]}:{props:[wl(i,o)]}},wa=(e,t)=>{4===e.type?e.content=e.isStatic?t+e.content:`\`${t}\${${e.content}}\``:(e.children.unshift(`'${t}' + (`),e.children.push(")"))},ka=(e,t)=>{if(0===e.type||1===e.type||11===e.type||10===e.type)return()=>{const n=e.children;let o,r=!1;for(let e=0;e7===e.type&&!t.directiveTransforms[e.name])))))for(let e=0;e{if(1===e.type&&Hl(e,"once",!0)){if(Ta.has(e)||t.inVOnce)return;return Ta.add(e),t.inVOnce=!0,t.helper(pl),()=>{t.inVOnce=!1;const e=t.currentNode;e.codegenNode&&(e.codegenNode=t.cache(e.codegenNode,!0))}}},Ea=(e,t,n)=>{const{exp:o,arg:r}=e;if(!o)return $a();const s=o.loc.source,i=4===o.type?o.content:s;if(!i.trim()||!Bl(i))return $a();const l=r||kl("modelValue",!0),c=r?Rl(r)?`onUpdate:${r.content}`:Tl(['"onUpdate:" + ',r]):"onUpdate:modelValue";let a;a=Tl([`${n.isTS?"($event: any)":"$event"} => ((`,o,") = $event)"]);const u=[wl(l,e.exp),wl(c,a)];if(e.modifiers.length&&1===t.tagType){const t=e.modifiers.map((e=>(Ml(e)?e:JSON.stringify(e))+": true")).join(", "),n=r?Rl(r)?`${r.content}Modifiers`:Tl([r,' + "Modifiers"']):"modelModifiers";u.push(wl(n,kl(`{ ${t} }`,!1,e.loc,2)))}return $a(u)};function $a(e=[]){return{props:e}}const Ra=new WeakSet,Oa=(e,t)=>{if(1===e.type){const n=Hl(e,"memo");if(!n||Ra.has(e))return;return Ra.add(e),()=>{const o=e.codegenNode||t.currentNode.codegenNode;o&&13===o.type&&(1!==e.tagType&&tc(o,t),e.codegenNode=Nl(t.helper(vl),[n.exp,El(void 0,o),"_cache",String(t.cached++)]))}}};function Aa(e,t={}){const n=t.onError||Oi,o="module"===t.mode;!0===t.prefixIdentifiers?n(Fi(46)):o&&n(Fi(47));t.cacheHandlers&&n(Fi(48)),t.scopeId&&!o&&n(Fi(49));const r=A(e)?sc(e,t):e,[s,i]=[[Na,Zc,Oa,ea,_a,ma,ca,ka],{on:xa,bind:Ca,model:Ea}];return Bc(r,C({},t,{prefixIdentifiers:false,nodeTransforms:[...s,...t.nodeTransforms||[]],directiveTransforms:C({},i,t.directiveTransforms||{})})),Hc(r,C({},t,{prefixIdentifiers:false}))}const Fa=Symbol(""),Ma=Symbol(""),Pa=Symbol(""),Va=Symbol(""),Ia=Symbol(""),Ba=Symbol(""),La=Symbol(""),ja=Symbol(""),Ua=Symbol(""),Ha=Symbol("");var Da;let Wa;Da={[Fa]:"vModelRadio",[Ma]:"vModelCheckbox",[Pa]:"vModelText",[Va]:"vModelSelect",[Ia]:"vModelDynamic",[Ba]:"withModifiers",[La]:"withKeys",[ja]:"vShow",[Ua]:"Transition",[Ha]:"TransitionGroup"},Object.getOwnPropertySymbols(Da).forEach((e=>{bl[e]=Da[e]}));const za=t("style,iframe,script,noscript",!0),Ka={isVoidTag:f,isNativeTag:e=>u(e)||p(e),isPreTag:e=>"pre"===e,decodeEntities:function(e,t=!1){return Wa||(Wa=document.createElement("div")),t?(Wa.innerHTML=`
`,Wa.children[0].getAttribute("foo")):(Wa.innerHTML=e,Wa.textContent)},isBuiltInComponent:e=>Ol(e,"Transition")?Ua:Ol(e,"TransitionGroup")?Ha:void 0,getNamespace(e,t){let n=t?t.ns:0;if(t&&2===n)if("annotation-xml"===t.tag){if("svg"===e)return 1;t.props.some((e=>6===e.type&&"encoding"===e.name&&null!=e.value&&("text/html"===e.value.content||"application/xhtml+xml"===e.value.content)))&&(n=0)}else/^m(?:[ions]|text)$/.test(t.tag)&&"mglyph"!==e&&"malignmark"!==e&&(n=0);else t&&1===n&&("foreignObject"!==t.tag&&"desc"!==t.tag&&"title"!==t.tag||(n=0));if(0===n){if("svg"===e)return 1;if("math"===e)return 2}return n},getTextMode({tag:e,ns:t}){if(0===t){if("textarea"===e||"title"===e)return 1;if(za(e))return 2}return 0}},Ga=(e,t)=>{const n=c(e);return kl(JSON.stringify(n),!1,t,3)};const qa=t("passive,once,capture"),Ja=t("stop,prevent,self,ctrl,shift,alt,meta,exact,middle"),Za=t("left,right"),Ya=t("onkeyup,onkeydown,onkeypress",!0),Qa=(e,t)=>Rl(e)&&"onclick"===e.content.toLowerCase()?kl(t,!0):4!==e.type?Tl(["(",e,`) === "onClick" ? "${t}" : (`,e,")"]):e,Xa=(e,t)=>{1!==e.type||0!==e.tagType||"script"!==e.tag&&"style"!==e.tag||t.removeNode()},eu=[e=>{1===e.type&&e.props.forEach(((t,n)=>{6===t.type&&"style"===t.name&&t.value&&(e.props[n]={type:7,name:"bind",arg:kl("style",!0,t.loc),exp:Ga(t.value.content,t.loc),modifiers:[],loc:t.loc})}))}],tu={cloak:()=>({props:[]}),html:(e,t,n)=>{const{exp:o,loc:r}=e;return t.children.length&&(t.children.length=0),{props:[wl(kl("innerHTML",!0,r),o||kl("",!0))]}},text:(e,t,n)=>{const{exp:o,loc:r}=e;return t.children.length&&(t.children.length=0),{props:[wl(kl("textContent",!0),o?Nl(n.helperString(tl),[o],r):kl("",!0))]}},model:(e,t,n)=>{const o=Ea(e,t,n);if(!o.props.length||1===t.tagType)return o;const{tag:r}=t,s=n.isCustomElement(r);if("input"===r||"textarea"===r||"select"===r||s){let e=Pa,i=!1;if("input"===r||s){const n=Dl(t,"type");if(n){if(7===n.type)e=Ia;else if(n.value)switch(n.value.content){case"radio":e=Fa;break;case"checkbox":e=Ma;break;case"file":i=!0}}else(function(e){return e.props.some((e=>!(7!==e.type||"bind"!==e.name||e.arg&&4===e.arg.type&&e.arg.isStatic)))})(t)&&(e=Ia)}else"select"===r&&(e=Va);i||(o.needRuntime=n.helper(e))}return o.props=o.props.filter((e=>!(4===e.key.type&&"modelValue"===e.key.content))),o},on:(e,t,n)=>xa(e,0,n,(t=>{const{modifiers:o}=e;if(!o.length)return t;let{key:r,value:s}=t.props[0];const{keyModifiers:i,nonKeyModifiers:l,eventOptionModifiers:c}=((e,t,n,o)=>{const r=[],s=[],i=[];for(let l=0;l({props:[],needRuntime:n.helper(ja)})};const nu=Object.create(null);function ou(e,t){if(!A(e)){if(!e.nodeType)return y;e=e.innerHTML}const n=e,o=nu[n];if(o)return o;if("#"===e[0]){const t=document.querySelector(e);e=t?t.innerHTML:""}const{code:r}=function(e,t={}){return Aa(e,C({},Ka,t,{nodeTransforms:[Xa,...eu,...t.nodeTransforms||[]],directiveTransforms:C({},tu,t.directiveTransforms||{}),transformHoist:null}))}(e,C({hoistStatic:!0,onError:void 0,onWarn:y},t)),s=new Function(r)();return s._rc=!0,nu[n]=s}return br(ou),e.BaseTransition=sn,e.Comment=Fo,e.EffectScope=te,e.Fragment=Oo,e.KeepAlive=vn,e.ReactiveEffect=de,e.Static=Mo,e.Suspense=Jt,e.Teleport=To,e.Text=Ao,e.Transition=Vs,e.TransitionGroup=ei,e.VueElement=Os,e.callWithAsyncErrorHandling=Rr,e.callWithErrorHandling=$r,e.camelize=D,e.capitalize=K,e.cloneVNode=Yo,e.compatUtils=null,e.compile=ou,e.computed=Pt,e.createApp=(...e)=>{const t=ki().createApp(...e),{mount:n}=t;return t.mount=e=>{const o=$i(e);if(!o)return;const r=t._component;O(r)||r.render||r.template||(r.template=o.innerHTML),o.innerHTML="";const s=n(o,!1,o instanceof SVGElement);return o instanceof Element&&(o.removeAttribute("v-cloak"),o.setAttribute("data-v-app","")),s},t},e.createBlock=Ho,e.createCommentVNode=function(e="",t=!1){return t?(Io(),Ho(Fo,null,e)):Jo(Fo,null,e)},e.createElementBlock=function(e,t,n,o,r,s){return Uo(qo(e,t,n,o,r,s,!0))},e.createElementVNode=qo,e.createHydrationRenderer=vo,e.createRenderer=go,e.createSSRApp=(...e)=>{const t=Ti().createApp(...e),{mount:n}=t;return t.mount=e=>{const t=$i(e);if(t)return n(t,!0,t instanceof SVGElement)},t},e.createSlots=function(e,t){for(let n=0;n{let e;return a||(e=a=t().catch((e=>{if(e=e instanceof Error?e:new Error(String(e)),l)return new Promise(((t,n)=>{l(e,(()=>t((u++,a=null,p()))),(()=>n(e)),u+1)}));throw e})).then((t=>e!==a&&a?a:(t&&(t.__esModule||"Module"===t[Symbol.toStringTag])&&(t=t.default),c=t,t))))};return dn({name:"AsyncComponentWrapper",__asyncLoader:p,get __asyncResolved(){return c},setup(){const e=ur;if(c)return()=>mn(c,e);const t=t=>{a=null,Or(t,e,13,!o)};if(i&&e.suspense)return p().then((t=>()=>mn(t,e))).catch((e=>(t(e),()=>o?Jo(o,{error:e}):null)));const l=kt(!1),u=kt(),f=kt(!!r);return r&&setTimeout((()=>{f.value=!1}),r),null!=s&&setTimeout((()=>{if(!l.value&&!u.value){const e=new Error(`Async component timed out after ${s}ms.`);t(e),u.value=e}}),s),p().then((()=>{l.value=!0,e.parent&&gn(e.parent.vnode)&&Kr(e.parent.update)})).catch((e=>{t(e),u.value=e})),()=>l.value&&c?mn(c,e):u.value&&o?Jo(o,{error:u.value}):n&&!f.value?Jo(n):void 0}})},e.defineComponent=dn,e.defineCustomElement=$s,e.defineEmits=function(){return null},e.defineExpose=function(e){},e.defineProps=function(){return null},e.defineSSRCustomElement=e=>$s(e,Ei),e.effect=function(e,t){e.effect&&(e=e.effect.fn);const n=new de(e);t&&(C(n,t),t.scope&&ne(n,t.scope)),t&&t.lazy||n.run();const o=n.run.bind(n);return o.effect=n,o},e.effectScope=function(e){return new te(e)},e.getCurrentInstance=pr,e.getCurrentScope=function(){return X},e.getTransitionRawChildren=fn,e.guardReactiveProps=Zo,e.h=cs,e.handleError=Or,e.hydrate=Ei,e.initCustomFormatter=function(){},e.initDirectivesForSSR=Ri,e.inject=nn,e.isMemoSame=us,e.isProxy=vt,e.isReactive=mt,e.isReadonly=gt,e.isRef=wt,e.isRuntimeOnly=()=>!mr,e.isVNode=Do,e.markRaw=bt,e.mergeDefaults=function(e,t){for(const n in t){const o=e[n];o?o.default=t[n]:null===o&&(e[n]={default:t[n]})}return e},e.mergeProps=nr,e.nextTick=zr,e.normalizeClass=a,e.normalizeProps=function(e){if(!e)return null;let{class:t,style:n}=e;return t&&!A(t)&&(e.class=a(t)),n&&(e.style=s(n)),e},e.normalizeStyle=s,e.onActivated=bn,e.onBeforeMount=Nn,e.onBeforeUnmount=On,e.onBeforeUpdate=$n,e.onDeactivated=_n,e.onErrorCaptured=Vn,e.onMounted=En,e.onRenderTracked=Pn,e.onRenderTriggered=Mn,e.onScopeDispose=function(e){X&&X.cleanups.push(e)},e.onServerPrefetch=Fn,e.onUnmounted=An,e.onUpdated=Rn,e.openBlock=Io,e.popScopeId=function(){Ut=null},e.provide=tn,e.proxyRefs=Rt,e.pushScopeId=function(e){Ut=e},e.queuePostFlushCb=Jr,e.reactive=pt,e.readonly=dt,e.ref=kt,e.registerRuntimeCompiler=br,e.render=Ni,e.renderList=function(e,t,n,o){let r;const s=n&&n[o];if(N(e)||A(e)){r=new Array(e.length);for(let n=0,o=e.length;nt(e,n,void 0,s&&s[n])));else{const n=Object.keys(e);r=new Array(n.length);for(let o=0,i=n.length;oe.devtools.emit(t,...n))),Vt=[];else{(o.__VUE_DEVTOOLS_HOOK_REPLAY__=o.__VUE_DEVTOOLS_HOOK_REPLAY__||[]).push((e=>{t(e,o)}))}},e.setTransitionHooks=pn,e.shallowReactive=ft,e.shallowReadonly=function(e){return ht(e,!0,Ie,st,at)},e.shallowRef=function(e){return Tt(e,!0)},e.ssrContextKey=as,e.ssrUtils=null,e.stop=function(e){e.effect.stop()},e.toDisplayString=e=>null==e?"":N(e)||M(e)&&(e.toString===V||!O(e.toString))?JSON.stringify(e,m,2):String(e),e.toHandlerKey=G,e.toHandlers=function(e){const t={};for(const n in e)t[G(n)]=e[n];return t},e.toRaw=yt,e.toRef=Ft,e.toRefs=function(e){const t=N(e)?new Array(e.length):{};for(const n in e)t[n]=Ft(e,n);return t},e.transformVNodeArgs=function(e){},e.triggerRef=function(e){Ct(e)},e.unref=Et,e.useAttrs=function(){return ls().attrs},e.useCssModule=function(e="$style"){return g},e.useCssVars=function(e){const t=pr();if(!t)return;const n=()=>As(t.subTree,e(t.proxy));es(n),En((()=>{const e=new MutationObserver(n);e.observe(t.subTree.el.parentNode,{childList:!0}),An((()=>e.disconnect()))}))},e.useSSRContext=()=>{},e.useSlots=function(){return ls().slots},e.useTransitionState=on,e.vModelCheckbox=ci,e.vModelDynamic=mi,e.vModelRadio=ui,e.vModelSelect=pi,e.vModelText=li,e.vShow=_i,e.version=ps,e.warn=function(e,...t){ve();const n=Tr.length?Tr[Tr.length-1].component:null,o=n&&n.appContext.config.warnHandler,r=function(){let e=Tr[Tr.length-1];if(!e)return[];const t=[];for(;e;){const n=t[0];n&&n.vnode===e?n.recurseCount++:t.push({vnode:e,recurseCount:0});const o=e.component&&e.component.parent;e=o&&o.vnode}return t}();if(o)$r(o,n,11,[e+t.join(""),n&&n.proxy,r.map((({vnode:e})=>`at <${kr(n,e.type)}>`)).join("\n"),r]);else{const n=[`[Vue warn]: ${e}`,...t];r.length&&n.push("\n",...function(e){const t=[];return e.forEach(((e,n)=>{t.push(...0===n?[]:["\n"],...function({vnode:e,recurseCount:t}){const n=t>0?`... (${t} recursive calls)`:"",o=` at <${kr(e.component,e.type,!!e.component&&null==e.component.parent)}`,r=">"+n;return e.props?[o,...Nr(e.props),r]:[o+r]}(e))})),t}(r)),console.warn(...n)}ye()},e.watch=ns,e.watchEffect=function(e,t){return os(e,null,t)},e.watchPostEffect=es,e.watchSyncEffect=function(e,t){return os(e,null,{flush:"sync"})},e.withAsyncContext=function(e){const t=pr();let n=e();return dr(),P(n)&&(n=n.catch((e=>{throw fr(t),e}))),[n,()=>fr(t)]},e.withCtx=Dt,e.withDefaults=function(e,t){return null},e.withDirectives=function(e,t){if(null===jt)return e;const n=jt.proxy,o=e.dirs||(e.dirs=[]);for(let r=0;rn=>{if(!("key"in n))return;const o=z(n.key);return t.some((e=>e===o||bi[e]===o))?e(n):void 0},e.withMemo=function(e,t,n,o){const r=n[o];if(r&&us(r,e))return r;const s=t();return s.memo=e.slice(),n[o]=s},e.withModifiers=(e,t)=>(n,...o)=>{for(let e=0;eDt,Object.defineProperty(e,"__esModule",{value:!0}),e}({}); diff --git a/core/static/core/style.scss b/core/static/core/style.scss index aa8c6c7f..f3ddd8f3 100644 --- a/core/static/core/style.scss +++ b/core/static/core/style.scss @@ -28,7 +28,7 @@ $twitblue: hsl(206, 82%, 63%); $shadow-color: rgb(223, 223, 223); -$background-bouton-color: hsl(0, 0%, 90%); +$background-button-color: hsl(0, 0%, 95%); /*--------------------------MEDIA QUERY HELPERS------------------------*/ $small-devices: 576px; @@ -47,10 +47,11 @@ body { input[type=button], input[type=submit], input[type=reset],input[type=file] { border: none; text-decoration: none; - background-color: $background-bouton-color; - padding: 10px; + background-color: $background-button-color; + padding: 0.4em; + margin: 0.1em; font-weight: bold; - font-size: 16px; + font-size: 1.2em; border-radius: 5px; cursor: pointer; box-shadow: $shadow-color 0px 0px 1px; @@ -62,9 +63,10 @@ input[type=button], input[type=submit], input[type=reset],input[type=file] { button{ border: none; text-decoration: none; - background-color: $background-bouton-color; - padding: 10px; - font-size: 14px; + background-color: $background-button-color; + padding: 0.4em; + margin: 0.1em; + font-size: 1.18em; border-radius: 5px; box-shadow: $shadow-color 0px 0px 1px; cursor: pointer; @@ -75,24 +77,26 @@ button{ input,textarea[type=text],[type=number]{ border: none; text-decoration: none; - background-color: $background-bouton-color; - padding: 7px; - font-size: 16px; + background-color: $background-button-color; + padding: 0.4em; + margin: 0.1em; + font-size: 1.2em; border-radius: 5px; + max-width: 95%; } textarea{ border: none; text-decoration: none; - background-color: $background-bouton-color; + background-color: $background-button-color; padding: 7px; - font-size: 16px; + font-size: 1.2em; border-radius: 5px; } select{ border: none; text-decoration: none; - font-size: 15px; - background-color: $background-bouton-color; + font-size: 1.2em; + background-color: $background-button-color; padding: 10px; border-radius: 5px; cursor: pointer; @@ -130,9 +134,10 @@ a { #header_language_chooser { position: absolute; - top: 0.2em; - right: 0.5em; + top: 2em; + left: 0.5em; width: 3%; + min-width: 2.2em; text-align: center; input { display: block; @@ -157,9 +162,6 @@ header { border-radius: 0px 0px 10px 10px; #header_logo { - display: inline-block; - flex: none; - background-size: 100% 100%; background-color: $white-color; padding: 0.2em; border-radius: 0px 0px 0px 9px; @@ -169,11 +171,19 @@ header { margin: 0px; width: 100%; height: 100%; + + img { + max-width: 70%; + max-height: 100%; + margin: auto; + display: block; + } } } #header_connect_links { margin: 0.6em 0.6em 0em auto; + padding: 0.2em; color: $white-color; form { display: inline; @@ -190,8 +200,9 @@ header { #header_bar { display: flex; flex: auto; + flex-wrap: wrap; width: 80%; - + a { text-decoration: none; margin: 0em 1em; @@ -203,7 +214,6 @@ header { } #header_bars_infos { - width: 35ch; flex: initial; list-style-type: none; margin: 0.2em 0.2em; @@ -213,12 +223,15 @@ header { display: inline-block; flex: auto; margin: 0.8em 0em; + input { + width: 14ch; + } } #header_user_links { display: flex; - width: 120ch; flex: initial; + flex-wrap: wrap; text-align: right; margin: 0em; div { @@ -287,42 +300,34 @@ header { #info_boxes { display: flex; + flex-wrap: wrap; width: 90%; margin: 1em auto; - p { - margin: 0px; - padding: 7px; - } #alert_box, #info_box { - font-size: 14px; - display: inline-block; - flex: auto; - padding: 2px; - margin: 0.2em 1.5%; - min-width: 10%; - max-width: 46%; - min-height: 20px; + flex: 49%; + font-size: 0.9em; + margin: 0.2em; + border-radius: 0.6em; + .markdown { + margin: 0.5em; + } &:before { - float: left; + font-family: FontAwesome; + font-size: 4em; + float: right; margin: 0.2em; } } #info_box { - border-radius: 10px; background: $primary-neutral-light-color; &:before { - font-family: FontAwesome; - font-size: 4em; content: "\f05a"; color: hsl(210, 100%, 56%); } } #alert_box { - border-radius: 10px; background: $second-color; &:before { - font-family: FontAwesome; - font-size: 4em; content: "\f06a"; color: $white-color; } @@ -345,12 +350,12 @@ header { a { flex: auto; text-align: center; - padding: 20px; + padding: 1.5em; color: $white-color; font-style: normal; font-weight: bolder; text-decoration: none; - + &:hover { background: $secondary-neutral-color; color: $white-color; @@ -458,6 +463,8 @@ header { /*---------------------------------NEWS--------------------------------*/ #news { + display: flex; + flex-wrap: wrap; .news_column { display: inline-block; margin: 0px; @@ -467,11 +474,13 @@ header { margin-bottom: 1em; } #right_column { - width: 20%; + flex: 20%; float: right; + margin: 0.2em; } #left_column { - width: 79%; + flex: 79%; + margin: 0.2em; h3 { background: $second-color; box-shadow: $shadow-color 1px 1px 1px; @@ -484,6 +493,11 @@ header { } } } + @media screen and (max-width: $small-devices){ + #left_column, #right_column { + flex: 100%; + } + } /* AGENDA/BIRTHDAYS */ #agenda,#birthdays { @@ -691,6 +705,12 @@ header { } } +@media screen and (max-width: $small-devices){ + #page { + width: 98%; + } +} + #news_details { display: inline-block; margin-top: 20px; @@ -723,7 +743,7 @@ header { text-align: center; text-decoration: none; display: inline-block; - font-size: 16px; + font-size: 1.2em; border-radius: 2px; float: right; display: block; @@ -1111,33 +1131,36 @@ u, .underline { text-decoration: underline; } -#basket { - width: 40%; - background: $primary-neutral-light-color; - float: right; - padding: 10px; - border-radius: 10px; -} - -#products { - width: 90%; - margin: 0px auto; - overflow: auto; -} - #bar_ui { - float: left; - min-width: 57%; -} + padding: 0.4em; + display: flex; + flex-wrap: wrap; + flex-direction: row-reverse; -#user_info_container {} + #products { + flex-basis: 100%; + margin: 0.2em; + overflow: auto; + } -#user_info { - float: right; - padding: 5px; - width: 40%; - margin: 0px auto; - background: $secondary-neutral-light-color; + #click_form { + flex: auto; + margin: 0.2em; + } + + #user_info { + flex: auto; + padding: 0.5em; + margin: 0.2em; + height: 100%; + background: $secondary-neutral-light-color; + img { + max-width: 70%; + } + input { + background: white; + } + } } /*-----------------------------USER PROFILE----------------------------*/ @@ -1212,6 +1235,11 @@ u, .underline { } } } + @media screen and (max-width: $small-devices){ + #user_profile_infos, #user_profile_pictures { + flex-basis: 50%; + } + } } } @@ -1412,6 +1440,7 @@ textarea { .search_bar { margin: 10px 0px; display: flex; + flex-wrap: wrap; height: 20p; align-items: center; } @@ -1551,6 +1580,7 @@ footer { color: $white-color; border-radius: 5px; display: flex; + flex-wrap: wrap; background-color: $primary-neutral-dark-color; box-shadow: $shadow-color 0px 0px 15px; a { @@ -2181,4 +2211,4 @@ $pedagogy-white-text: #f0f0f0; } } } -} \ No newline at end of file +} diff --git a/core/templates/core/base.jinja b/core/templates/core/base.jinja index d2dc7e93..ea251677 100644 --- a/core/templates/core/base.jinja +++ b/core/templates/core/base.jinja @@ -3,6 +3,7 @@ {% block head %} {% block title %}{% trans %}Welcome!{% endtrans %}{% endblock %} - Association des Étudiants UTBM + @@ -27,6 +28,7 @@ {% block header %} {% if not popup %} +
{% for language in LANGUAGES %}
{% csrf_token %} @@ -37,10 +39,11 @@ {% endfor %}
-
{% if not user.is_authenticated %} -
- {% set sith = get_sith() %} - {% if sith.alert_msg %} -
- {{ sith.alert_msg|markdown }} -
- {% endif %} - {% if sith.info_msg %} -
- {{ sith.info_msg|markdown }} -
- {% endif %} + {% block info_boxes %} + {% set sith = get_sith() %} + {% if sith.alert_msg %} +
+ {{ sith.alert_msg|markdown }} +
+ {% endif %} + {% if sith.info_msg %} +
+ {{ sith.info_msg|markdown }} +
+ {% endif %} + {% endblock %}
{% else %}{# if not popup #} diff --git a/core/templates/core/delete_confirm.jinja b/core/templates/core/delete_confirm.jinja index f5c5de24..a439c9e0 100644 --- a/core/templates/core/delete_confirm.jinja +++ b/core/templates/core/delete_confirm.jinja @@ -4,6 +4,12 @@ {% trans %}Delete confirmation{% endtrans %} {% endblock %} +{% block info_boxes %} +{% endblock %} + +{% block nav %} +{% endblock %} + {% block content %}

{% trans %}Delete confirmation{% endtrans %}

{% csrf_token %} diff --git a/core/templates/core/user_edit.jinja b/core/templates/core/user_edit.jinja index b88cab79..5bd692e9 100644 --- a/core/templates/core/user_edit.jinja +++ b/core/templates/core/user_edit.jinja @@ -52,6 +52,7 @@ {% if not form.instance.profile_pict %} {{ super() }} + diff --git a/counter/templates/counter/counter_main.jinja b/counter/templates/counter/counter_main.jinja index 39942111..e0dd2380 100644 --- a/counter/templates/counter/counter_main.jinja +++ b/counter/templates/counter/counter_main.jinja @@ -12,6 +12,12 @@ {% trans counter_name=counter %}{{ counter_name }} counter{% endtrans %} {% endblock %} +{% block info_boxes %} +{% endblock %} + +{% block nav %} +{% endblock %} + {% block content %}

{% trans counter_name=counter %}{{ counter_name }} counter{% endtrans %}

diff --git a/counter/templates/counter/last_ops.jinja b/counter/templates/counter/last_ops.jinja index c7f0c4af..00e10bfa 100644 --- a/counter/templates/counter/last_ops.jinja +++ b/counter/templates/counter/last_ops.jinja @@ -5,6 +5,12 @@ {% trans counter_name=counter %}{{ counter_name }} last operations{% endtrans %} {% endblock %} +{% block info_boxes %} +{% endblock %} + +{% block nav %} +{% endblock %} + {% block content %}

{% trans counter_name=counter %}{{ counter_name }} last operations{% endtrans %}

{% trans %}Refillings{% endtrans %}

diff --git a/counter/tests.py b/counter/tests.py index a2fd6303..c0a9b40e 100644 --- a/counter/tests.py +++ b/counter/tests.py @@ -68,18 +68,29 @@ class CounterTest(TestCase): location, { "action": "refill", - "amount": "10", + "amount": "5", "payment_method": "CASH", "bank": "OTHER", }, ) response = self.client.post(location, {"action": "code", "code": "BARB"}) + response = self.client.post( + location, {"action": "add_product", "product_id": "4"} + ) + response = self.client.post( + location, {"action": "del_product", "product_id": "4"} + ) + response = self.client.post(location, {"action": "code", "code": "2xdeco"}) + response = self.client.post(location, {"action": "code", "code": "1xbarb"}) response = self.client.post(location, {"action": "code", "code": "fin"}) response_get = self.client.get(response.get("location")) + response_content = response_get.content.decode("utf-8") + self.assertTrue("
  • 2 x Barbar" in str(response_content)) + self.assertTrue("
  • 2 x Déconsigne Eco-cup" in str(response_content)) self.assertTrue( - "

    Client : Richard Batsbak - Nouveau montant : 8.30" - in str(response_get.content) + "

    Client : Richard Batsbak - Nouveau montant : 3.60" + in str(response_content) ) diff --git a/counter/views.py b/counter/views.py index 2ce9480a..e03831e1 100644 --- a/counter/views.py +++ b/counter/views.py @@ -38,7 +38,7 @@ from django.views.generic.edit import ( from django.forms.models import modelform_factory from django.forms import CheckboxSelectMultiple from django.urls import reverse_lazy, reverse -from django.http import HttpResponseRedirect, HttpResponse +from django.http import HttpResponseRedirect, HttpResponse, JsonResponse from django.utils import timezone from django import forms from django.utils.translation import ugettext_lazy as _ @@ -48,6 +48,7 @@ from django.db import DataError, transaction, models import re import pytz from datetime import date, timedelta, datetime +from http import HTTPStatus from ajax_select.fields import AutoCompleteSelectField, AutoCompleteSelectMultipleField from ajax_select import make_ajax_field @@ -69,6 +70,7 @@ from counter.models import ( Permanency, ) from accounting.models import CurrencyField +from core.views.forms import TzAwareDateTimeField class CounterAdminMixin(View): @@ -357,6 +359,34 @@ class CounterClick(CounterTabsMixin, CanViewMixin, DetailView): pk_url_kwarg = "counter_id" current_tab = "counter" + def render_to_response(self, *args, **kwargs): + if self.request.is_ajax(): # JSON response for AJAX requests + response = {"errors": []} + status = HTTPStatus.OK + + if self.request.session["too_young"]: + response["errors"].append(_("Too young for that product")) + status = HTTPStatus.UNAVAILABLE_FOR_LEGAL_REASONS + if self.request.session["not_allowed"]: + response["errors"].append(_("Not allowed for that product")) + status = HTTPStatus.FORBIDDEN + if self.request.session["no_age"]: + response["errors"].append(_("No date of birth provided")) + status = HTTPStatus.UNAVAILABLE_FOR_LEGAL_REASONS + if self.request.session["not_enough"]: + response["errors"].append(_("Not enough money")) + status = HTTPStatus.PAYMENT_REQUIRED + + if len(response["errors"]) > 1: + status = HTTPStatus.BAD_REQUEST + + response["basket"] = self.request.session["basket"] + + return JsonResponse(response, status=status) + + else: # Standard HTML page + return super().render_to_response(*args, **kwargs) + def dispatch(self, request, *args, **kwargs): self.customer = get_object_or_404(Customer, user__id=self.kwargs["user_id"]) obj = self.get_object() @@ -370,7 +400,9 @@ class CounterClick(CounterTabsMixin, CanViewMixin, DetailView): ) or len(obj.get_barmen_list()) < 1 ): - raise PermissionDenied + return HttpResponseRedirect( + reverse_lazy("counter:details", kwargs={"counter_id": obj.id}) + ) else: if not request.user.is_authenticated: raise PermissionDenied @@ -394,7 +426,7 @@ class CounterClick(CounterTabsMixin, CanViewMixin, DetailView): return ret def post(self, request, *args, **kwargs): - """ Handle the many possibilities of the post request """ + """Handle the many possibilities of the post request""" self.object = self.get_object() self.refill_form = None if (self.object.type != "BAR" and not request.user.is_authenticated) or ( @@ -590,7 +622,7 @@ class CounterClick(CounterTabsMixin, CanViewMixin, DetailView): return True def del_product(self, request): - """ Delete a product from the basket """ + """Delete a product from the basket""" pid = str(request.POST["product_id"]) product = self.get_product(pid) if pid in request.session["basket"]: @@ -632,7 +664,7 @@ class CounterClick(CounterTabsMixin, CanViewMixin, DetailView): return self.render_to_response(context) def finish(self, request): - """ Finish the click session, and validate the basket """ + """Finish the click session, and validate the basket""" with transaction.atomic(): request.session["last_basket"] = [] if self.sum_basket(request) > self.customer.amount: @@ -684,7 +716,7 @@ class CounterClick(CounterTabsMixin, CanViewMixin, DetailView): ) def cancel(self, request): - """ Cancel the click session """ + """Cancel the click session""" kwargs = {"counter_id": self.object.id} request.session.pop("basket", None) return HttpResponseRedirect( @@ -706,7 +738,7 @@ class CounterClick(CounterTabsMixin, CanViewMixin, DetailView): raise PermissionDenied def get_context_data(self, **kwargs): - """ Add customer to the context """ + """Add customer to the context""" kwargs = super(CounterClick, self).get_context_data(**kwargs) kwargs["products"] = self.object.products.select_related("product_type") kwargs["categories"] = {} @@ -1360,7 +1392,7 @@ class CounterLastOperationsView(CounterTabsMixin, CanViewMixin, DetailView): ) def get_context_data(self, **kwargs): - """Add form to the context """ + """Add form to the context""" kwargs = super(CounterLastOperationsView, self).get_context_data(**kwargs) threshold = timezone.now() - timedelta( minutes=settings.SITH_LAST_OPERATIONS_LIMIT @@ -1422,7 +1454,7 @@ class CounterCashSummaryView(CounterTabsMixin, CanViewMixin, DetailView): return reverse_lazy("counter:details", kwargs={"counter_id": self.object.id}) def get_context_data(self, **kwargs): - """ Add form to the context """ + """Add form to the context""" kwargs = super(CounterCashSummaryView, self).get_context_data(**kwargs) kwargs["form"] = self.form return kwargs @@ -1448,7 +1480,7 @@ class CounterStatView(DetailView, CounterAdminMixin): template_name = "counter/stats.jinja" def get_context_data(self, **kwargs): - """ Add stats to the context """ + """Add stats to the context""" from django.db.models import Sum, Case, When, F, DecimalField kwargs = super(CounterStatView, self).get_context_data(**kwargs) @@ -1553,18 +1585,8 @@ class CashSummaryEditView(CounterAdminTabsMixin, CounterAdminMixin, UpdateView): class CashSummaryFormBase(forms.Form): - begin_date = forms.DateTimeField( - input_formats=["%Y-%m-%d %H:%M:%S"], - label=_("Begin date"), - required=False, - widget=SelectDateTime, - ) - end_date = forms.DateTimeField( - input_formats=["%Y-%m-%d %H:%M:%S"], - label=_("End date"), - required=False, - widget=SelectDateTime, - ) + begin_date = TzAwareDateTimeField(label=_("Begin date"), required=False) + end_date = TzAwareDateTimeField(label=_("End date"), required=False) class CashSummaryListView(CounterAdminTabsMixin, CounterAdminMixin, ListView): @@ -1578,7 +1600,7 @@ class CashSummaryListView(CounterAdminTabsMixin, CounterAdminMixin, ListView): paginate_by = settings.SITH_COUNTER_CASH_SUMMARY_LENGTH def get_context_data(self, **kwargs): - """ Add sums to the context """ + """Add sums to the context""" kwargs = super(CashSummaryListView, self).get_context_data(**kwargs) form = CashSummaryFormBase(self.request.GET) kwargs["form"] = form @@ -1629,7 +1651,7 @@ class InvoiceCallView(CounterAdminTabsMixin, CounterAdminMixin, TemplateView): current_tab = "invoices_call" def get_context_data(self, **kwargs): - """ Add sums to the context """ + """Add sums to the context""" kwargs = super(InvoiceCallView, self).get_context_data(**kwargs) kwargs["months"] = Selling.objects.datetimes("date", "month", order="DESC") start_date = None diff --git a/doc/start/install.rst b/doc/start/install.rst index 5a8c9226..502835f0 100644 --- a/doc/start/install.rst +++ b/doc/start/install.rst @@ -133,3 +133,14 @@ Pour lancer les tests il suffit d'utiliser la commande intégrée à django. # Lancer une méthode en particulier de cette même classe ./manage.py test core.tests.UserRegistrationTest.test_register_user_form_ok + +Vérifier les dépendances Javascript +----------------------------------- + +Une commande a été écrite pour vérifier les éventuelles mises à jour à faire sur les librairies Javascript utilisées. +N'oubliez pas de mettre à jour à la fois le fichier de la librairie, mais également sa version dans `sith/settings.py`. + +.. code-block:: bash + + # Vérifier les mises à jour + ./manage.py check_front diff --git a/eboutic/views.py b/eboutic/views.py index 45d79249..35b5e09b 100644 --- a/eboutic/views.py +++ b/eboutic/views.py @@ -82,7 +82,7 @@ class EbouticMain(TemplateView): return self.render_to_response(self.get_context_data(**kwargs)) def add_product(self, request): - """ Add a product to the basket """ + """Add a product to the basket""" try: p = self.object.products.filter(id=int(request.POST["product_id"])).first() if not p.buying_groups.exists(): @@ -95,7 +95,7 @@ class EbouticMain(TemplateView): pass def del_product(self, request): - """ Delete a product from the basket """ + """Delete a product from the basket""" try: p = self.object.products.filter(id=int(request.POST["product_id"])).first() self.basket.del_product(p) diff --git a/election/views.py b/election/views.py index 78342cd2..ad0cdb3e 100644 --- a/election/views.py +++ b/election/views.py @@ -14,6 +14,7 @@ from core.views import CanViewMixin, CanEditMixin, CanCreateMixin from django.db.models.query import QuerySet from core.views.forms import SelectDateTime, MarkdownInput from election.models import Election, Role, Candidature, ElectionList, Vote +from core.views.forms import TzAwareDateTimeField from ajax_select.fields import AutoCompleteSelectField from ajax_select import make_ajax_field @@ -24,8 +25,8 @@ from ajax_select import make_ajax_field class LimitedCheckboxField(forms.ModelMultipleChoiceField): """ - Used to replace ModelMultipleChoiceField but with - automatic backend verification + Used to replace ModelMultipleChoiceField but with + automatic backend verification """ def __init__(self, queryset, max_choice, **kwargs): @@ -49,7 +50,7 @@ class LimitedCheckboxField(forms.ModelMultipleChoiceField): class CandidateForm(forms.ModelForm): - """ Form to candidate """ + """Form to candidate""" class Meta: model = Candidature @@ -95,7 +96,7 @@ class VoteForm(forms.Form): class RoleForm(forms.ModelForm): - """ Form for creating a role """ + """Form for creating a role""" class Meta: model = Role @@ -167,30 +168,12 @@ class ElectionForm(forms.ModelForm): label=_("candidature groups"), ) - start_date = forms.DateTimeField( - input_formats=["%Y-%m-%d %H:%M:%S"], - label=_("Start date"), - widget=SelectDateTime, - required=True, - ) - end_date = forms.DateTimeField( - input_formats=["%Y-%m-%d %H:%M:%S"], - label=_("End date"), - widget=SelectDateTime, - required=True, - ) - start_candidature = forms.DateTimeField( - input_formats=["%Y-%m-%d %H:%M:%S"], - label=_("Start candidature"), - widget=SelectDateTime, - required=True, - ) - end_candidature = forms.DateTimeField( - input_formats=["%Y-%m-%d %H:%M:%S"], - label=_("End candidature"), - widget=SelectDateTime, - required=True, + start_date = TzAwareDateTimeField(label=_("Start date"), required=True) + end_date = TzAwareDateTimeField(label=_("End date"), required=True) + start_candidature = TzAwareDateTimeField( + label=_("Start candidature"), required=True ) + end_candidature = TzAwareDateTimeField(label=_("End candidature"), required=True) # Display elections @@ -261,7 +244,7 @@ class ElectionDetailView(CanViewMixin, DetailView): return r def get_context_data(self, **kwargs): - """ Add additionnal data to the template """ + """Add additionnal data to the template""" kwargs = super(ElectionDetailView, self).get_context_data(**kwargs) kwargs["election_form"] = VoteForm(self.object, self.request.user) kwargs["election_results"] = self.object.results @@ -308,7 +291,7 @@ class VoteFormView(CanCreateMixin, FormView): def form_valid(self, form): """ - Verify that the user is part in a vote group + Verify that the user is part in a vote group """ data = form.clean() res = super(FormView, self).form_valid(form) @@ -322,7 +305,7 @@ class VoteFormView(CanCreateMixin, FormView): return reverse_lazy("election:detail", kwargs={"election_id": self.election.id}) def get_context_data(self, **kwargs): - """ Add additionnal data to the template """ + """Add additionnal data to the template""" kwargs = super(VoteFormView, self).get_context_data(**kwargs) kwargs["object"] = self.election kwargs["election"] = self.election @@ -360,7 +343,7 @@ class CandidatureCreateView(CanCreateMixin, CreateView): def form_valid(self, form): """ - Verify that the selected user is in candidate group + Verify that the selected user is in candidate group """ obj = form.instance obj.election = Election.objects.get(id=self.election.id) @@ -391,8 +374,8 @@ class ElectionCreateView(CanCreateMixin, CreateView): def form_valid(self, form): """ - Allow every users that had passed the dispatch - to create an election + Allow every users that had passed the dispatch + to create an election """ return super(CreateView, self).form_valid(form) @@ -418,7 +401,7 @@ class RoleCreateView(CanCreateMixin, CreateView): def form_valid(self, form): """ - Verify that the user can edit proprely + Verify that the user can edit proprely """ obj = form.instance if obj.election: @@ -461,7 +444,7 @@ class ElectionListCreateView(CanCreateMixin, CreateView): def form_valid(self, form): """ - Verify that the user can vote on this election + Verify that the user can vote on this election """ obj = form.instance if obj.election: diff --git a/launderette/views.py b/launderette/views.py index 7b5f5ad8..a7672102 100644 --- a/launderette/views.py +++ b/launderette/views.py @@ -52,7 +52,7 @@ class LaunderetteMainView(TemplateView): template_name = "launderette/launderette_main.jinja" def get_context_data(self, **kwargs): - """ Add page to the context """ + """Add page to the context""" kwargs = super(LaunderetteMainView, self).get_context_data(**kwargs) kwargs["page"] = Page.objects.filter(name="launderette").first() return kwargs @@ -142,7 +142,7 @@ class LaunderetteBookView(CanViewMixin, DetailView): currentDate += delta def get_context_data(self, **kwargs): - """ Add page to the context """ + """Add page to the context""" kwargs = super(LaunderetteBookView, self).get_context_data(**kwargs) kwargs["planning"] = OrderedDict() kwargs["slot_type"] = self.slot_type @@ -481,7 +481,7 @@ class LaunderetteClickView(CanEditMixin, DetailView, BaseFormView): return super(LaunderetteClickView, self).get(request, *args, **kwargs) def post(self, request, *args, **kwargs): - """ Handle the many possibilities of the post request """ + """Handle the many possibilities of the post request""" self.object = self.get_object() self.customer = Customer.objects.filter(user__id=self.kwargs["user_id"]).first() self.subscriber = self.customer.user diff --git a/locale/fr/LC_MESSAGES/django.po b/locale/fr/LC_MESSAGES/django.po index 2b00bab8..33fca100 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: 2019-11-13 23:14+0100\n" +"POT-Creation-Date: 2021-09-29 16:08+0200\n" "PO-Revision-Date: 2016-07-18\n" "Last-Translator: Skia \n" "Language-Team: AE info \n" @@ -21,7 +21,7 @@ msgstr "" #: com/models.py:294 counter/models.py:121 counter/models.py:149 #: counter/models.py:213 forum/models.py:58 launderette/models.py:38 #: launderette/models.py:93 launderette/models.py:131 stock/models.py:40 -#: stock/models.py:63 stock/models.py:105 stock/models.py:134 +#: stock/models.py:63 stock/models.py:105 stock/models.py:133 msgid "name" msgstr "nom" @@ -41,7 +41,7 @@ msgstr "code postal" msgid "country" msgstr "pays" -#: accounting/models.py:66 core/models.py:258 +#: accounting/models.py:66 core/models.py:281 msgid "phone" msgstr "téléphone" @@ -127,10 +127,10 @@ msgstr "numéro" msgid "journal" msgstr "classeur" -#: accounting/models.py:290 core/models.py:825 core/models.py:1363 -#: core/models.py:1411 core/models.py:1440 core/models.py:1464 +#: accounting/models.py:290 core/models.py:848 core/models.py:1386 +#: core/models.py:1434 core/models.py:1463 core/models.py:1487 #: counter/models.py:364 counter/models.py:457 counter/models.py:662 -#: eboutic/models.py:46 eboutic/models.py:93 forum/models.py:311 +#: eboutic/models.py:47 eboutic/models.py:100 forum/models.py:311 #: forum/models.py:408 stock/models.py:104 msgid "date" msgstr "date" @@ -149,7 +149,7 @@ msgstr "méthode de paiement" msgid "cheque number" msgstr "numéro de chèque" -#: accounting/models.py:303 eboutic/models.py:178 +#: accounting/models.py:303 eboutic/models.py:185 msgid "invoice" msgstr "facture" @@ -166,7 +166,7 @@ msgid "accounting type" msgstr "type comptable" #: accounting/models.py:328 accounting/models.py:475 accounting/models.py:510 -#: accounting/models.py:545 core/models.py:1439 core/models.py:1465 +#: accounting/models.py:545 core/models.py:1462 core/models.py:1488 #: counter/models.py:423 msgid "label" msgstr "étiquette" @@ -200,7 +200,7 @@ msgstr "Utilisateur" #: com/templates/com/news_admin_list.jinja:288 #: com/templates/com/weekmail.jinja:18 com/templates/com/weekmail.jinja:47 #: core/templates/core/user_clubs.jinja:15 -#: core/templates/core/user_clubs.jinja:41 +#: core/templates/core/user_clubs.jinja:44 #: counter/templates/counter/invoices_call.jinja:23 #: trombi/templates/trombi/edit_profile.jinja:15 #: trombi/templates/trombi/edit_profile.jinja:22 @@ -219,7 +219,7 @@ msgstr "Compte" msgid "Company" msgstr "Entreprise" -#: accounting/models.py:341 sith/settings.py:379 +#: accounting/models.py:341 sith/settings.py:380 #: stock/templates/stock/shopping_list_items.jinja:37 msgid "Other" msgstr "Autre" @@ -367,11 +367,14 @@ msgstr "Compte en banque : " #: core/templates/core/group_list.jinja:25 core/templates/core/macros.jinja:93 #: core/templates/core/macros.jinja:112 core/templates/core/page_prop.jinja:14 #: core/templates/core/user_account_detail.jinja:38 +#: core/templates/core/user_account_detail.jinja:66 +#: core/templates/core/user_clubs.jinja:32 +#: core/templates/core/user_clubs.jinja:61 #: core/templates/core/user_detail.jinja:178 #: core/templates/core/user_edit.jinja:19 #: core/templates/core/user_preferences.jinja:36 -#: counter/templates/counter/last_ops.jinja:29 -#: counter/templates/counter/last_ops.jinja:59 +#: counter/templates/counter/last_ops.jinja:35 +#: counter/templates/counter/last_ops.jinja:65 #: election/templates/election/election_detail.jinja:271 #: election/templates/election/election_detail.jinja:286 #: election/templates/election/election_detail.jinja:350 @@ -392,7 +395,7 @@ msgid "Delete" msgstr "Supprimer" #: accounting/templates/accounting/bank_account_details.jinja:18 -#: club/views.py:78 core/views/user.py:196 sas/templates/sas/picture.jinja:86 +#: club/views.py:88 core/views/user.py:196 sas/templates/sas/picture.jinja:86 msgid "Infos" msgstr "Infos" @@ -411,7 +414,7 @@ msgstr "Nouveau compte club" #: accounting/templates/accounting/bank_account_details.jinja:27 #: accounting/templates/accounting/bank_account_list.jinja:22 #: accounting/templates/accounting/club_account_details.jinja:58 -#: accounting/templates/accounting/journal_details.jinja:89 club/views.py:124 +#: accounting/templates/accounting/journal_details.jinja:89 club/views.py:134 #: com/templates/com/news_admin_list.jinja:39 #: com/templates/com/news_admin_list.jinja:68 #: com/templates/com/news_admin_list.jinja:115 @@ -522,7 +525,7 @@ msgstr "Fin" #: accounting/templates/accounting/journal_details.jinja:35 #: core/templates/core/user_account_detail.jinja:53 #: core/templates/core/user_account_detail.jinja:80 -#: counter/templates/counter/last_ops.jinja:17 +#: counter/templates/counter/last_ops.jinja:23 #: counter/templates/counter/refilling_list.jinja:13 msgid "Amount" msgstr "Montant" @@ -532,7 +535,7 @@ msgid "Effective amount" msgstr "Montant effectif" #: accounting/templates/accounting/club_account_details.jinja:36 -#: sith/settings.py:423 +#: sith/settings.py:424 msgid "Closed" msgstr "Fermé" @@ -601,7 +604,7 @@ msgstr "Classeur : " #: accounting/templates/accounting/journal_statement_accounting.jinja:30 #: core/templates/core/user_account.jinja:38 #: core/templates/core/user_account_detail.jinja:10 -#: counter/templates/counter/counter_click.jinja:32 +#: counter/templates/counter/counter_click.jinja:21 msgid "Amount: " msgstr "Montant : " @@ -631,9 +634,9 @@ msgstr "No" #: core/templates/core/user_account_detail.jinja:50 #: core/templates/core/user_account_detail.jinja:78 #: counter/templates/counter/cash_summary_list.jinja:34 -#: counter/templates/counter/last_ops.jinja:14 -#: counter/templates/counter/last_ops.jinja:39 -#: rootplace/templates/rootplace/logs.jinja:12 sas/views.py:369 +#: counter/templates/counter/last_ops.jinja:20 +#: counter/templates/counter/last_ops.jinja:45 +#: rootplace/templates/rootplace/logs.jinja:12 sas/views.py:375 #: stock/templates/stock/stock_shopping_list.jinja:25 #: stock/templates/stock/stock_shopping_list.jinja:54 #: trombi/templates/trombi/user_profile.jinja:40 @@ -643,7 +646,7 @@ msgstr "Date" #: accounting/templates/accounting/journal_details.jinja:34 #: club/templates/club/club_sellings.jinja:24 #: core/templates/core/user_account_detail.jinja:20 -#: counter/templates/counter/last_ops.jinja:42 +#: counter/templates/counter/last_ops.jinja:48 #: rootplace/templates/rootplace/logs.jinja:14 msgid "Label" msgstr "Étiquette" @@ -657,7 +660,7 @@ msgid "Target" msgstr "Cible" #: accounting/templates/accounting/journal_details.jinja:38 -#: core/views/forms.py:94 +#: core/views/forms.py:98 msgid "Code" msgstr "Code" @@ -671,7 +674,7 @@ msgid "Done" msgstr "Effectuées" #: accounting/templates/accounting/journal_details.jinja:41 -#: counter/templates/counter/cash_summary_list.jinja:37 counter/views.py:1168 +#: counter/templates/counter/cash_summary_list.jinja:37 counter/views.py:1200 #: pedagogy/templates/pedagogy/moderation.jinja:13 #: pedagogy/templates/pedagogy/uv_detail.jinja:138 #: trombi/templates/trombi/comment.jinja:4 @@ -735,8 +738,7 @@ msgstr "Nature de l'opération" #: accounting/templates/accounting/journal_statement_nature.jinja:26 #: accounting/templates/accounting/journal_statement_nature.jinja:45 #: club/templates/club/club_sellings.jinja:14 -#: counter/templates/counter/counter_click.jinja:90 -#: counter/templates/counter/counter_main.jinja:28 +#: counter/templates/counter/counter_main.jinja:34 msgid "Total: " msgstr "Total : " @@ -793,7 +795,7 @@ msgstr "Opération liée : " #: core/templates/core/user_preferences.jinja:12 #: core/templates/core/user_preferences.jinja:19 #: core/templates/core/user_preferences.jinja:31 -#: counter/templates/counter/cash_register_summary.jinja:22 +#: counter/templates/counter/cash_register_summary.jinja:28 #: forum/templates/forum/reply.jinja:33 #: subscription/templates/subscription/subscription.jinja:25 #: trombi/templates/trombi/comment.jinja:26 @@ -909,99 +911,97 @@ msgstr "Opérations sans étiquette" msgid "Refound this account" msgstr "Rembourser ce compte" -#: club/forms.py:60 club/forms.py:188 +#: club/forms.py:61 club/forms.py:194 msgid "Users to add" msgstr "Utilisateurs à ajouter" -#: club/forms.py:61 club/forms.py:189 core/views/group.py:63 +#: club/forms.py:62 club/forms.py:195 core/views/group.py:63 msgid "Search users to add (one or more)." msgstr "Recherche les utilisateurs à ajouter (un ou plus)." -#: club/forms.py:70 -#, fuzzy -#| msgid "New mailing" +#: club/forms.py:71 msgid "New Mailing" msgstr "Nouvelle mailing liste" -#: club/forms.py:71 -#, fuzzy -#| msgid "Unsubscribe" +#: club/forms.py:72 msgid "Subscribe" -msgstr "Se désabonner" +msgstr "S'abonner" -#: club/forms.py:72 club/forms.py:85 com/templates/com/news_admin_list.jinja:40 +#: club/forms.py:73 club/forms.py:86 com/templates/com/news_admin_list.jinja:40 #: com/templates/com/news_admin_list.jinja:116 #: com/templates/com/news_admin_list.jinja:198 #: com/templates/com/news_admin_list.jinja:274 msgid "Remove" msgstr "Retirer" -#: club/forms.py:75 launderette/views.py:228 +#: club/forms.py:76 launderette/views.py:228 #: pedagogy/templates/pedagogy/moderation.jinja:15 msgid "Action" msgstr "Action" -#: club/forms.py:115 club/tests.py:575 -#, fuzzy -#| msgid "This field is required." +#: club/forms.py:116 club/tests.py:575 msgid "This field is required" -msgstr "Ce champ est obligatoire." +msgstr "Ce champ est obligatoire" -#: club/forms.py:127 club/forms.py:250 club/tests.py:587 +#: club/forms.py:128 club/forms.py:256 club/tests.py:587 msgid "One of the selected users doesn't exist" msgstr "Un des utilisateurs sélectionné n'existe pas" -#: club/forms.py:131 club/tests.py:605 -#, fuzzy -#| msgid "One of the selected users doesn't exist" +#: club/forms.py:132 club/tests.py:605 msgid "One of the selected users doesn't have an email address" -msgstr "Un des utilisateurs sélectionné n'existe pas" +msgstr "Un des utilisateurs sélectionnés n'a pas d'adresse email" -#: club/forms.py:142 -#, fuzzy -#| msgid "This field is required." +#: club/forms.py:143 msgid "An action is required" -msgstr "Ce champ est obligatoire." +msgstr "Une action est requise" -#: club/forms.py:153 club/tests.py:564 +#: club/forms.py:154 club/tests.py:564 msgid "You must specify at least an user or an email address" msgstr "vous devez spécifier au moins un utilisateur ou une adresse email" -#: club/forms.py:163 counter/views.py:1558 +#: club/forms.py:162 counter/views.py:1588 msgid "Begin date" msgstr "Date de début" -#: club/forms.py:169 com/views.py:85 com/views.py:210 counter/views.py:1564 -#: election/views.py:178 subscription/views.py:52 +#: club/forms.py:163 com/views.py:83 com/views.py:198 counter/views.py:1589 +#: election/views.py:172 subscription/views.py:49 msgid "End date" msgstr "Date de fin" -#: club/forms.py:174 club/templates/club/club_sellings.jinja:21 +#: club/forms.py:166 club/templates/club/club_sellings.jinja:21 #: core/templates/core/user_account_detail.jinja:18 #: core/templates/core/user_account_detail.jinja:51 -#: counter/templates/counter/cash_summary_list.jinja:33 counter/views.py:214 +#: counter/templates/counter/cash_summary_list.jinja:33 counter/views.py:216 msgid "Counter" msgstr "Comptoir" -#: club/forms.py:232 club/templates/club/club_members.jinja:21 +#: club/forms.py:174 counter/views.py:829 +msgid "Products" +msgstr "Produits" + +#: club/forms.py:179 counter/views.py:834 +msgid "Archived products" +msgstr "Produits archivés" + +#: club/forms.py:238 club/templates/club/club_members.jinja:21 #: club/templates/club/club_members.jinja:46 #: core/templates/core/user_clubs.jinja:29 msgid "Mark as old" msgstr "Marquer comme ancien" -#: club/forms.py:254 +#: club/forms.py:260 msgid "User must be subscriber to take part to a club" msgstr "L'utilisateur doit être cotisant pour faire partie d'un club" -#: club/forms.py:258 core/views/group.py:82 +#: club/forms.py:264 core/views/group.py:82 msgid "You can not add the same user twice" msgstr "Vous ne pouvez pas ajouter deux fois le même utilisateur" -#: club/forms.py:279 +#: club/forms.py:285 msgid "You should specify a role" msgstr "Vous devez choisir un rôle" -#: club/forms.py:290 sas/views.py:130 sas/views.py:196 sas/views.py:295 +#: club/forms.py:296 sas/views.py:130 sas/views.py:202 sas/views.py:301 msgid "You do not have the permission to do that" msgstr "Vous n'avez pas la permission de faire cela" @@ -1033,11 +1033,11 @@ msgstr "actif" msgid "short description" msgstr "description courte" -#: club/models.py:74 core/models.py:260 +#: club/models.py:74 core/models.py:283 msgid "address" msgstr "Adresse" -#: club/models.py:94 core/models.py:173 +#: club/models.py:94 core/models.py:196 msgid "home" msgstr "home" @@ -1050,18 +1050,18 @@ msgid "A club with that unix_name already exists" msgstr "Un club avec ce nom UNIX existe déjà." #: club/models.py:267 counter/models.py:623 counter/models.py:653 -#: eboutic/models.py:42 eboutic/models.py:89 election/models.py:192 +#: eboutic/models.py:43 eboutic/models.py:96 election/models.py:192 #: launderette/models.py:145 launderette/models.py:213 sas/models.py:244 #: trombi/models.py:213 msgid "user" msgstr "nom d'utilisateur" -#: club/models.py:284 core/models.py:224 election/models.py:187 +#: club/models.py:284 core/models.py:247 election/models.py:187 #: election/models.py:223 trombi/models.py:218 msgid "role" msgstr "rôle" -#: club/models.py:289 core/models.py:73 counter/models.py:122 +#: club/models.py:289 core/models.py:81 counter/models.py:122 #: counter/models.py:150 election/models.py:15 election/models.py:120 #: election/models.py:197 forum/models.py:59 forum/models.py:240 msgid "description" @@ -1080,7 +1080,7 @@ msgid "Enter a valid address. Only the root of the address is needed." msgstr "" "Entrez une adresse valide. Seule la racine de l'adresse est nécessaire." -#: club/models.py:353 com/models.py:83 com/models.py:310 core/models.py:826 +#: club/models.py:353 com/models.py:83 com/models.py:310 core/models.py:849 msgid "is moderated" msgstr "est modéré" @@ -1132,7 +1132,7 @@ msgstr "Membres du club" #: club/templates/club/club_members.jinja:17 #: club/templates/club/club_old_members.jinja:9 #: core/templates/core/user_clubs.jinja:16 -#: core/templates/core/user_clubs.jinja:42 +#: core/templates/core/user_clubs.jinja:45 #: trombi/templates/trombi/edit_profile.jinja:23 #: trombi/templates/trombi/export.jinja:56 #: trombi/templates/trombi/user_profile.jinja:39 @@ -1143,7 +1143,7 @@ msgstr "Rôle" #: club/templates/club/club_old_members.jinja:10 #: core/templates/core/group_list.jinja:15 #: core/templates/core/user_clubs.jinja:17 -#: core/templates/core/user_clubs.jinja:43 +#: core/templates/core/user_clubs.jinja:46 msgid "Description" msgstr "Description" @@ -1158,7 +1158,7 @@ msgid "There are no members in this club." msgstr "Il n'y a pas de membres dans ce club." #: club/templates/club/club_members.jinja:78 -#: core/templates/core/file_detail.jinja:19 core/views/forms.py:337 +#: core/templates/core/file_detail.jinja:19 core/views/forms.py:335 #: launderette/views.py:226 trombi/templates/trombi/detail.jinja:19 msgid "Add" msgstr "Ajouter" @@ -1168,18 +1168,18 @@ msgid "Club old members" msgstr "Anciens membres du club" #: club/templates/club/club_old_members.jinja:11 -#: core/templates/core/user_clubs.jinja:44 +#: core/templates/core/user_clubs.jinja:47 msgid "From" msgstr "Du" #: club/templates/club/club_old_members.jinja:12 -#: core/templates/core/user_clubs.jinja:45 +#: core/templates/core/user_clubs.jinja:48 msgid "To" msgstr "Au" -#: club/templates/club/club_sellings.jinja:5 club/views.py:144 -#: club/views.py:378 counter/templates/counter/counter_main.jinja:19 -#: counter/templates/counter/last_ops.jinja:35 +#: club/templates/club/club_sellings.jinja:5 club/views.py:154 +#: club/views.py:483 counter/templates/counter/counter_main.jinja:25 +#: counter/templates/counter/last_ops.jinja:41 msgid "Sellings" msgstr "Ventes" @@ -1207,15 +1207,15 @@ msgstr "Bénéfice : " #: club/templates/club/club_sellings.jinja:22 #: core/templates/core/user_account_detail.jinja:19 #: core/templates/core/user_account_detail.jinja:52 -#: counter/templates/counter/last_ops.jinja:15 -#: counter/templates/counter/last_ops.jinja:40 +#: counter/templates/counter/last_ops.jinja:21 +#: counter/templates/counter/last_ops.jinja:46 msgid "Barman" msgstr "Barman" #: club/templates/club/club_sellings.jinja:23 -#: counter/templates/counter/counter_click.jinja:29 -#: counter/templates/counter/last_ops.jinja:16 -#: counter/templates/counter/last_ops.jinja:41 +#: counter/templates/counter/counter_click.jinja:18 +#: counter/templates/counter/last_ops.jinja:22 +#: counter/templates/counter/last_ops.jinja:47 #: counter/templates/counter/refilling_list.jinja:12 msgid "Customer" msgstr "Client" @@ -1223,7 +1223,7 @@ msgstr "Client" #: club/templates/club/club_sellings.jinja:25 #: core/templates/core/user_account_detail.jinja:21 #: core/templates/core/user_stats.jinja:28 -#: counter/templates/counter/last_ops.jinja:43 +#: counter/templates/counter/last_ops.jinja:49 msgid "Quantity" msgstr "Quantité" @@ -1231,7 +1231,7 @@ msgstr "Quantité" #: core/templates/core/user_account.jinja:10 #: core/templates/core/user_account_detail.jinja:22 #: counter/templates/counter/cash_summary_list.jinja:35 -#: counter/templates/counter/last_ops.jinja:44 +#: counter/templates/counter/last_ops.jinja:50 #: counter/templates/counter/stats.jinja:18 #: subscription/templates/subscription/stats.jinja:40 #: subscription/templates/subscription/stats.jinja:48 @@ -1242,8 +1242,8 @@ msgstr "Total" #: core/templates/core/user_account_detail.jinja:23 #: core/templates/core/user_account_detail.jinja:54 #: core/templates/core/user_detail.jinja:148 -#: counter/templates/counter/last_ops.jinja:18 -#: counter/templates/counter/last_ops.jinja:45 +#: counter/templates/counter/last_ops.jinja:24 +#: counter/templates/counter/last_ops.jinja:51 #: counter/templates/counter/refilling_list.jinja:14 msgid "Payment method" msgstr "Méthode de paiement" @@ -1354,46 +1354,41 @@ msgstr "Aucune page n'existe pour ce club" msgid "Club stats" msgstr "Statistiques du club" -#: club/views.py:88 +#: club/views.py:98 msgid "Members" msgstr "Membres" -#: club/views.py:97 +#: club/views.py:107 msgid "Old members" msgstr "Anciens membres" -#: club/views.py:107 core/templates/core/page.jinja:33 +#: club/views.py:117 core/templates/core/page.jinja:33 msgid "History" msgstr "Historique" -#: club/views.py:115 core/templates/core/base.jinja:118 core/views/user.py:219 -#: sas/templates/sas/picture.jinja:95 trombi/views.py:61 +#: club/views.py:125 core/templates/core/base.jinja:118 core/views/user.py:219 +#: sas/templates/sas/picture.jinja:95 trombi/views.py:63 msgid "Tools" msgstr "Outils" -#: club/views.py:135 +#: club/views.py:145 msgid "Edit club page" msgstr "Éditer la page de club" -#: club/views.py:151 +#: club/views.py:161 msgid "Mailing list" msgstr "Listes de diffusion" -#: club/views.py:160 com/views.py:138 +#: club/views.py:170 com/views.py:133 msgid "Posters list" msgstr "Liste d'affiches" -#: club/views.py:170 counter/templates/counter/counter_list.jinja:21 +#: club/views.py:180 counter/templates/counter/counter_list.jinja:21 #: counter/templates/counter/counter_list.jinja:43 #: counter/templates/counter/counter_list.jinja:59 msgid "Props" msgstr "Propriétés" -#: club/views.py:335 core/templates/core/user_stats.jinja:27 -#: counter/views.py:1712 -msgid "Product" -msgstr "Produit" - #: com/models.py:46 msgid "alert message" msgstr "message d'alerte" @@ -1436,9 +1431,9 @@ msgstr "résumé" msgid "content" msgstr "contenu" -#: com/models.py:72 core/models.py:1409 launderette/models.py:101 +#: com/models.py:72 core/models.py:1432 launderette/models.py:101 #: launderette/models.py:139 launderette/models.py:196 stock/models.py:80 -#: stock/models.py:138 +#: stock/models.py:137 msgid "type" msgstr "type" @@ -1487,7 +1482,7 @@ msgstr "weekmail" msgid "rank" msgstr "rang" -#: com/models.py:296 core/models.py:791 core/models.py:841 +#: com/models.py:296 core/models.py:814 core/models.py:864 msgid "file" msgstr "fichier" @@ -1499,7 +1494,7 @@ msgstr "temps d'affichage" msgid "Begin date should be before end date" msgstr "La date de début doit être avant celle de fin" -#: com/templates/com/mailing_admin.jinja:4 com/views.py:131 +#: com/templates/com/mailing_admin.jinja:4 com/views.py:126 #: core/templates/core/user_tools.jinja:90 msgid "Mailing lists administration" msgstr "Administration des mailing listes" @@ -1583,7 +1578,7 @@ msgstr "Type" #: com/templates/com/news_admin_list.jinja:286 #: com/templates/com/weekmail.jinja:19 com/templates/com/weekmail.jinja:48 #: forum/templates/forum/forum.jinja:24 forum/templates/forum/forum.jinja:43 -#: forum/templates/forum/main.jinja:27 forum/views.py:243 +#: forum/templates/forum/main.jinja:27 forum/views.py:244 #: pedagogy/templates/pedagogy/guide.jinja:60 msgid "Title" msgstr "Titre" @@ -1654,7 +1649,7 @@ msgid "Calls to moderate" msgstr "Appels à modérer" #: com/templates/com/news_admin_list.jinja:242 -#: core/templates/core/base.jinja:170 +#: core/templates/core/base.jinja:172 msgid "Events" msgstr "Événements" @@ -1730,7 +1725,7 @@ msgstr "Anniversaires" msgid "%(age)s year old" msgstr "%(age)s ans" -#: com/templates/com/news_list.jinja:61 com/tests.py:109 com/tests.py:119 +#: com/templates/com/news_list.jinja:61 com/tests.py:112 com/tests.py:122 msgid "You need an up to date subscription to access this content" msgstr "Votre cotisation doit être à jour pour accéder à cette section" @@ -1811,7 +1806,7 @@ msgid "Slideshow" msgstr "Diaporama" #: com/templates/com/weekmail.jinja:5 com/templates/com/weekmail.jinja:9 -#: com/views.py:108 core/templates/core/user_tools.jinja:83 +#: com/views.py:103 core/templates/core/user_tools.jinja:83 msgid "Weekmail" msgstr "Weekmail" @@ -1900,86 +1895,90 @@ msgstr "Astuce" msgid "Final word" msgstr "Le mot de la fin" -#: com/views.py:78 com/views.py:204 election/views.py:172 +#: com/views.py:76 +msgid "Format: 16:9 | Resolution: 1920x1080" +msgstr "Format : 16:9 | Résolution : 1920x1080" + +#: com/views.py:79 com/views.py:197 election/views.py:171 #: subscription/views.py:46 msgid "Start date" msgstr "Date de début" -#: com/views.py:103 +#: com/views.py:98 msgid "Communication administration" msgstr "Administration de la communication" -#: com/views.py:114 core/templates/core/user_tools.jinja:84 +#: com/views.py:109 core/templates/core/user_tools.jinja:84 msgid "Weekmail destinations" msgstr "Destinataires du Weekmail" -#: com/views.py:118 +#: com/views.py:113 msgid "Info message" msgstr "Message d'info" -#: com/views.py:124 +#: com/views.py:119 msgid "Alert message" msgstr "Message d'alerte" -#: com/views.py:145 +#: com/views.py:140 msgid "Screens list" msgstr "Liste d'écrans" -#: com/views.py:216 +#: com/views.py:199 msgid "Until" msgstr "Jusqu'à" -#: com/views.py:220 +#: com/views.py:201 msgid "Automoderation" msgstr "Automodération" -#: com/views.py:227 com/views.py:231 com/views.py:245 +#: com/views.py:208 com/views.py:212 com/views.py:226 msgid "This field is required." msgstr "Ce champ est obligatoire." -#: com/views.py:241 +#: com/views.py:222 msgid "You crazy? You can not finish an event before starting it." msgstr "T'es fou? Un événement ne peut pas finir avant même de commencer." -#: com/views.py:470 +#: com/views.py:451 msgid "Delete and save to regenerate" msgstr "Supprimer et sauver pour regénérer" -#: com/views.py:485 +#: com/views.py:466 msgid "Weekmail of the " msgstr "Weekmail du " -#: com/views.py:595 +#: com/views.py:576 msgid "" "You must be a board member of the selected club to post in the Weekmail." msgstr "" "Vous devez êtres un membre du bureau du club sélectionné pour poster dans le " "Weekmail." -#: core/models.py:69 +#: core/models.py:76 msgid "meta group status" msgstr "status du meta-groupe" -#: core/models.py:71 +#: core/models.py:78 msgid "Whether a group is a meta group or not" msgstr "Si un groupe est un meta-groupe ou pas" -#: core/models.py:108 +#: core/models.py:131 #, python-format msgid "%(value)s is not a valid promo (between 0 and %(end)s)" msgstr "%(value)s n'est pas une promo valide (doit être entre 0 et %(end)s)" -#: core/models.py:126 +#: core/models.py:149 msgid "username" msgstr "nom d'utilisateur" -#: core/models.py:130 +#: core/models.py:153 msgid "Required. 254 characters or fewer. Letters, digits and ./+/-/_ only." msgstr "" "Requis. Pas plus de 254 caractères. Uniquement des lettres, numéros, et ./" "+/-/_" -#: core/models.py:136 +#: core/models.py:159 msgid "" "Enter a valid username. This value may contain only letters, numbers and ./" "+/-/_ characters." @@ -1987,43 +1986,43 @@ msgstr "" "Entrez un nom d'utilisateur correct. Uniquement des lettres, numéros, et ./" "+/-/_" -#: core/models.py:142 +#: core/models.py:165 msgid "A user with that username already exists." msgstr "Un utilisateur de ce nom existe déjà" -#: core/models.py:144 +#: core/models.py:167 msgid "first name" msgstr "Prénom" -#: core/models.py:145 +#: core/models.py:168 msgid "last name" msgstr "Nom" -#: core/models.py:146 +#: core/models.py:169 msgid "email address" msgstr "adresse email" -#: core/models.py:147 +#: core/models.py:170 msgid "date of birth" msgstr "date de naissance" -#: core/models.py:148 +#: core/models.py:171 msgid "nick name" msgstr "surnom" -#: core/models.py:150 +#: core/models.py:173 msgid "staff status" msgstr "status \"staff\"" -#: core/models.py:152 +#: core/models.py:175 msgid "Designates whether the user can log into this admin site." msgstr "Est-ce que l'utilisateur peut se logger à la partie admin du site." -#: core/models.py:155 +#: core/models.py:178 msgid "active" msgstr "actif" -#: core/models.py:158 +#: core/models.py:181 msgid "" "Designates whether this user should be treated as active. Unselect this " "instead of deleting accounts." @@ -2031,43 +2030,43 @@ msgstr "" "Est-ce que l'utilisateur doit être traité comme actif. Déselectionnez au " "lieu de supprimer les comptes." -#: core/models.py:162 +#: core/models.py:185 msgid "date joined" msgstr "date d'inscription" -#: core/models.py:163 +#: core/models.py:186 msgid "last update" msgstr "dernière mise à jour" -#: core/models.py:165 +#: core/models.py:188 msgid "superuser" msgstr "super-utilisateur" -#: core/models.py:167 +#: core/models.py:190 msgid "Designates whether this user is a superuser. " msgstr "Est-ce que l'utilisateur est super-utilisateur." -#: core/models.py:181 +#: core/models.py:204 msgid "profile" msgstr "profil" -#: core/models.py:189 +#: core/models.py:212 msgid "avatar" msgstr "avatar" -#: core/models.py:197 +#: core/models.py:220 msgid "scrub" msgstr "blouse" -#: core/models.py:203 +#: core/models.py:226 msgid "sex" msgstr "Genre" -#: core/models.py:205 matmat/views.py:74 +#: core/models.py:228 matmat/views.py:74 msgid "Man" msgstr "Homme" -#: core/models.py:205 matmat/views.py:75 +#: core/models.py:228 matmat/views.py:75 msgid "Woman" msgstr "Femme" @@ -2079,115 +2078,115 @@ msgstr "Pronoms" msgid "tshirt size" msgstr "taille de tshirt" -#: core/models.py:212 +#: core/models.py:235 msgid "-" msgstr "-" -#: core/models.py:213 +#: core/models.py:236 msgid "XS" msgstr "XS" -#: core/models.py:214 +#: core/models.py:237 msgid "S" msgstr "S" -#: core/models.py:215 +#: core/models.py:238 msgid "M" msgstr "M" -#: core/models.py:216 +#: core/models.py:239 msgid "L" msgstr "L" -#: core/models.py:217 +#: core/models.py:240 msgid "XL" msgstr "XL" -#: core/models.py:218 +#: core/models.py:241 msgid "XXL" msgstr "XXL" -#: core/models.py:219 +#: core/models.py:242 msgid "XXXL" msgstr "XXXL" -#: core/models.py:227 +#: core/models.py:250 msgid "Student" msgstr "Étudiant" -#: core/models.py:228 +#: core/models.py:251 msgid "Administrative agent" msgstr "Personnel administratif" -#: core/models.py:229 +#: core/models.py:252 msgid "Teacher" msgstr "Enseignant" -#: core/models.py:230 +#: core/models.py:253 msgid "Agent" msgstr "Personnel" -#: core/models.py:231 +#: core/models.py:254 msgid "Doctor" msgstr "Doctorant" -#: core/models.py:232 +#: core/models.py:255 msgid "Former student" msgstr "Ancien étudiant" -#: core/models.py:233 +#: core/models.py:256 msgid "Service" msgstr "Service" -#: core/models.py:239 +#: core/models.py:262 msgid "department" msgstr "département" -#: core/models.py:246 +#: core/models.py:269 msgid "dpt option" msgstr "Filière" -#: core/models.py:248 pedagogy/models.py:74 pedagogy/models.py:303 +#: core/models.py:271 pedagogy/models.py:74 pedagogy/models.py:303 msgid "semester" msgstr "semestre" -#: core/models.py:249 +#: core/models.py:272 msgid "quote" msgstr "citation" -#: core/models.py:250 +#: core/models.py:273 msgid "school" msgstr "école" -#: core/models.py:252 +#: core/models.py:275 msgid "promo" msgstr "promo" -#: core/models.py:255 +#: core/models.py:278 msgid "forum signature" msgstr "signature du forum" -#: core/models.py:257 +#: core/models.py:280 msgid "second email address" msgstr "adresse email secondaire" -#: core/models.py:259 +#: core/models.py:282 msgid "parent phone" msgstr "téléphone des parents" -#: core/models.py:262 +#: core/models.py:285 msgid "parent address" msgstr "adresse des parents" -#: core/models.py:265 +#: core/models.py:288 msgid "is subscriber viewable" msgstr "profil visible par les cotisants" -#: core/models.py:480 +#: core/models.py:503 msgid "A user with that username already exists" msgstr "Un utilisateur de ce nom d'utilisateur existe déjà" -#: core/models.py:618 core/templates/core/macros.jinja:72 +#: core/models.py:641 core/templates/core/macros.jinja:72 #: core/templates/core/macros.jinja:74 core/templates/core/macros.jinja:75 #: core/templates/core/user_detail.jinja:79 #: core/templates/core/user_detail.jinja:80 @@ -2205,109 +2204,109 @@ msgstr "Un utilisateur de ce nom d'utilisateur existe déjà" msgid "Profile" msgstr "Profil" -#: core/models.py:742 +#: core/models.py:765 msgid "Visitor" msgstr "Visiteur" -#: core/models.py:750 +#: core/models.py:773 msgid "do you want to receive the weekmail" msgstr "voulez-vous recevoir le Weekmail" -#: core/models.py:752 +#: core/models.py:775 msgid "show your stats to others" msgstr "montrez vos statistiques aux autres" -#: core/models.py:754 +#: core/models.py:777 msgid "get a notification for every click" msgstr "recevez une notification pour chaque click" -#: core/models.py:757 +#: core/models.py:780 msgid "get a notification for every refilling" msgstr "recevez une notification pour chaque rechargement" -#: core/models.py:780 +#: core/models.py:803 msgid "file name" msgstr "nom du fichier" -#: core/models.py:784 core/models.py:1132 +#: core/models.py:807 core/models.py:1155 msgid "parent" msgstr "parent" -#: core/models.py:798 +#: core/models.py:821 msgid "compressed file" msgstr "version allégée" -#: core/models.py:805 +#: core/models.py:828 msgid "thumbnail" msgstr "miniature" -#: core/models.py:813 core/models.py:830 +#: core/models.py:836 core/models.py:853 msgid "owner" msgstr "propriétaire" -#: core/models.py:817 core/models.py:1152 core/views/files.py:191 +#: core/models.py:840 core/models.py:1175 core/views/files.py:191 msgid "edit group" msgstr "groupe d'édition" -#: core/models.py:820 core/models.py:1155 core/views/files.py:194 +#: core/models.py:843 core/models.py:1178 core/views/files.py:194 msgid "view group" msgstr "groupe de vue" -#: core/models.py:822 +#: core/models.py:845 msgid "is folder" msgstr "est un dossier" -#: core/models.py:823 +#: core/models.py:846 msgid "mime type" msgstr "type mime" -#: core/models.py:824 +#: core/models.py:847 msgid "size" msgstr "taille" -#: core/models.py:835 +#: core/models.py:858 msgid "asked for removal" msgstr "retrait demandé" -#: core/models.py:837 +#: core/models.py:860 msgid "is in the SAS" msgstr "est dans le SAS" -#: core/models.py:879 +#: core/models.py:902 msgid "Character '/' not authorized in name" msgstr "Le caractère '/' n'est pas autorisé dans les noms de fichier" -#: core/models.py:881 core/models.py:885 +#: core/models.py:904 core/models.py:908 msgid "Loop in folder tree" msgstr "Boucle dans l'arborescence des dossiers" -#: core/models.py:888 +#: core/models.py:911 msgid "You can not make a file be a children of a non folder file" msgstr "" "Vous ne pouvez pas mettre un fichier enfant de quelque chose qui n'est pas " "un dossier" -#: core/models.py:899 +#: core/models.py:922 msgid "Duplicate file" msgstr "Un fichier de ce nom existe déjà" -#: core/models.py:916 +#: core/models.py:939 msgid "You must provide a file" msgstr "Vous devez fournir un fichier" -#: core/models.py:1056 +#: core/models.py:1079 msgid "Folder: " msgstr "Dossier : " -#: core/models.py:1058 +#: core/models.py:1081 msgid "File: " msgstr "Fichier : " -#: core/models.py:1115 +#: core/models.py:1138 msgid "page unix name" msgstr "nom unix de la page" -#: core/models.py:1121 +#: core/models.py:1144 msgid "" "Enter a valid page name. This value may contain only unaccented letters, " "numbers and ./+/-/_ characters." @@ -2315,55 +2314,55 @@ msgstr "" "Entrez un nom de page correct. Uniquement des lettres non accentuées, " "numéros, et ./+/-/_" -#: core/models.py:1139 +#: core/models.py:1162 msgid "page name" msgstr "nom de la page" -#: core/models.py:1147 +#: core/models.py:1170 msgid "owner group" msgstr "groupe propriétaire" -#: core/models.py:1160 +#: core/models.py:1183 msgid "lock user" msgstr "utilisateur bloquant" -#: core/models.py:1167 +#: core/models.py:1190 msgid "lock_timeout" msgstr "décompte du déblocage" -#: core/models.py:1197 +#: core/models.py:1220 msgid "Duplicate page" msgstr "Une page de ce nom existe déjà" -#: core/models.py:1200 +#: core/models.py:1223 msgid "Loop in page tree" msgstr "Boucle dans l'arborescence des pages" -#: core/models.py:1360 +#: core/models.py:1383 msgid "revision" msgstr "révision" -#: core/models.py:1361 +#: core/models.py:1384 msgid "page title" msgstr "titre de la page" -#: core/models.py:1362 +#: core/models.py:1385 msgid "page content" msgstr "contenu de la page" -#: core/models.py:1406 +#: core/models.py:1429 msgid "url" msgstr "url" -#: core/models.py:1407 +#: core/models.py:1430 msgid "param" msgstr "param" -#: core/models.py:1412 +#: core/models.py:1435 msgid "viewed" msgstr "vue" -#: core/models.py:1470 +#: core/models.py:1493 msgid "operation type" msgstr "type d'opération" @@ -2423,51 +2422,51 @@ msgstr "Marquer tout commme lu" msgid "Logout" msgstr "Déconnexion" -#: core/templates/core/base.jinja:154 +#: core/templates/core/base.jinja:156 msgid "Main" msgstr "Accueil" -#: core/templates/core/base.jinja:156 +#: core/templates/core/base.jinja:158 msgid "Associations & Clubs" msgstr "Associations & Clubs" -#: core/templates/core/base.jinja:160 +#: core/templates/core/base.jinja:162 msgid "AE" msgstr "L'AE" -#: core/templates/core/base.jinja:161 +#: core/templates/core/base.jinja:163 msgid "AE's clubs" msgstr "Les clubs de L'AE" -#: core/templates/core/base.jinja:162 +#: core/templates/core/base.jinja:164 msgid "BdF" msgstr "Le BdF" -#: core/templates/core/base.jinja:163 +#: core/templates/core/base.jinja:165 msgid "BDS" msgstr "Le BDS" -#: core/templates/core/base.jinja:164 +#: core/templates/core/base.jinja:166 msgid "CETU" msgstr "Le CETU" -#: core/templates/core/base.jinja:165 +#: core/templates/core/base.jinja:167 msgid "Doceo" msgstr "Doceo" -#: core/templates/core/base.jinja:166 +#: core/templates/core/base.jinja:168 msgid "Positions" msgstr "Postes à pourvoir" -#: core/templates/core/base.jinja:174 +#: core/templates/core/base.jinja:176 msgid "Calendar" msgstr "Calendrier" -#: core/templates/core/base.jinja:175 +#: core/templates/core/base.jinja:177 msgid "Big event" msgstr "Grandes Activités" -#: core/templates/core/base.jinja:178 +#: core/templates/core/base.jinja:180 #: forum/templates/forum/favorite_topics.jinja:14 #: forum/templates/forum/last_unread.jinja:14 #: forum/templates/forum/macros.jinja:90 forum/templates/forum/main.jinja:6 @@ -2476,89 +2475,89 @@ msgstr "Grandes Activités" msgid "Forum" msgstr "Forum" -#: core/templates/core/base.jinja:179 +#: core/templates/core/base.jinja:181 msgid "Gallery" msgstr "Photos" -#: core/templates/core/base.jinja:180 counter/models.py:223 +#: core/templates/core/base.jinja:182 counter/models.py:223 #: counter/templates/counter/counter_list.jinja:11 #: eboutic/templates/eboutic/eboutic_main.jinja:4 #: eboutic/templates/eboutic/eboutic_main.jinja:24 #: eboutic/templates/eboutic/eboutic_makecommand.jinja:8 #: eboutic/templates/eboutic/eboutic_payment_result.jinja:4 -#: sith/settings.py:378 sith/settings.py:386 +#: sith/settings.py:379 sith/settings.py:387 msgid "Eboutic" msgstr "Eboutic" -#: core/templates/core/base.jinja:182 +#: core/templates/core/base.jinja:184 msgid "Services" msgstr "Services" -#: core/templates/core/base.jinja:186 +#: core/templates/core/base.jinja:188 msgid "Matmatronch" msgstr "Matmatronch" -#: core/templates/core/base.jinja:187 launderette/models.py:47 +#: core/templates/core/base.jinja:189 launderette/models.py:47 #: launderette/templates/launderette/launderette_book.jinja:5 #: launderette/templates/launderette/launderette_book_choose.jinja:4 #: launderette/templates/launderette/launderette_main.jinja:4 msgid "Launderette" msgstr "Laverie" -#: core/templates/core/base.jinja:188 core/templates/core/file.jinja:20 +#: core/templates/core/base.jinja:190 core/templates/core/file.jinja:20 #: core/views/files.py:84 msgid "Files" msgstr "Fichiers" -#: core/templates/core/base.jinja:189 core/templates/core/user_tools.jinja:109 +#: core/templates/core/base.jinja:191 core/templates/core/user_tools.jinja:109 msgid "Pedagogy" msgstr "Pédagogie" -#: core/templates/core/base.jinja:193 +#: core/templates/core/base.jinja:195 msgid "My Benefits" msgstr "Mes Avantages" -#: core/templates/core/base.jinja:197 +#: core/templates/core/base.jinja:199 msgid "Sponsors" msgstr "Partenaires" -#: core/templates/core/base.jinja:198 +#: core/templates/core/base.jinja:200 msgid "Subscriber benefits" msgstr "Les avantages cotisants" -#: core/templates/core/base.jinja:202 +#: core/templates/core/base.jinja:204 msgid "Help" msgstr "Aide" -#: core/templates/core/base.jinja:206 +#: core/templates/core/base.jinja:208 msgid "FAQ" msgstr "FAQ" -#: core/templates/core/base.jinja:207 core/templates/core/base.jinja:249 +#: core/templates/core/base.jinja:209 core/templates/core/base.jinja:251 msgid "Contacts" msgstr "Contacts" -#: core/templates/core/base.jinja:208 +#: core/templates/core/base.jinja:210 msgid "Wiki" msgstr "Wiki" -#: core/templates/core/base.jinja:250 +#: core/templates/core/base.jinja:252 msgid "Legal notices" msgstr "Mentions légales" -#: core/templates/core/base.jinja:251 +#: core/templates/core/base.jinja:253 msgid "Intellectual property" msgstr "Propriété intellectuelle" -#: core/templates/core/base.jinja:252 +#: core/templates/core/base.jinja:254 msgid "Help & Documentation" msgstr "Aide & Documentation" -#: core/templates/core/base.jinja:253 +#: core/templates/core/base.jinja:255 msgid "R&D" msgstr "R&D" -#: core/templates/core/base.jinja:255 +#: core/templates/core/base.jinja:257 msgid "Site made by good people" msgstr "Site réalisé par des gens bons" @@ -2587,7 +2586,7 @@ msgstr "Confirmation" #: core/templates/core/delete_confirm.jinja:14 #: core/templates/core/file_delete_confirm.jinja:14 -#: counter/templates/counter/counter_click.jinja:113 +#: counter/templates/counter/counter_click.jinja:103 msgid "Cancel" msgstr "Annuler" @@ -2600,7 +2599,7 @@ msgstr "Éditer %(obj)s" #: core/templates/core/file.jinja:7 core/templates/core/file_list.jinja:6 msgid "File list" -msgstr "Liste des fichiers" +msgstr "Liste de fichiers" #: core/templates/core/file.jinja:9 msgid "New file" @@ -2739,7 +2738,7 @@ msgid "Please login or create an account to see this page." msgstr "Merci de vous identifier ou de créer un compte pour voir cette page." #: core/templates/core/login.jinja:28 -#: counter/templates/counter/counter_main.jinja:51 +#: counter/templates/counter/counter_main.jinja:57 msgid "login" msgstr "login" @@ -2777,23 +2776,23 @@ msgstr "Créneau" msgid "Tokens" msgstr "Jetons" -#: core/templates/core/macros.jinja:119 core/templates/core/macros.jinja:121 +#: core/templates/core/macros.jinja:120 core/templates/core/macros.jinja:122 msgid "Previous" msgstr "Précédent" -#: core/templates/core/macros.jinja:125 +#: core/templates/core/macros.jinja:126 msgid "current" msgstr "actuel" -#: core/templates/core/macros.jinja:131 core/templates/core/macros.jinja:133 +#: core/templates/core/macros.jinja:132 core/templates/core/macros.jinja:134 msgid "Next" msgstr "Suivant" -#: core/templates/core/macros.jinja:149 +#: core/templates/core/macros.jinja:150 msgid "Select All" msgstr "Tout sélectionner" -#: core/templates/core/macros.jinja:150 +#: core/templates/core/macros.jinja:151 msgid "Unselect All" msgstr "Tout désélectionner" @@ -2874,7 +2873,7 @@ msgstr "Retourner à la gestion du club" #: core/templates/core/page.jinja:49 msgid "Page does not exist" -msgstr "La page n'existe pas." +msgstr "La page n'existe pas" #: core/templates/core/page.jinja:51 msgid "Create it?" @@ -3056,7 +3055,7 @@ msgstr "Achat sur compte utilisateur" #: core/templates/core/user_account.jinja:48 #: core/templates/core/user_account_detail.jinja:46 #: counter/templates/counter/cash_summary_list.jinja:17 -#: counter/templates/counter/last_ops.jinja:10 +#: counter/templates/counter/last_ops.jinja:16 msgid "Refillings" msgstr "Rechargements" @@ -3066,7 +3065,7 @@ msgid "Eboutic invoices" msgstr "Facture eboutic" #: core/templates/core/user_account.jinja:57 -#: core/templates/core/user_tools.jinja:37 counter/views.py:822 +#: core/templates/core/user_tools.jinja:37 counter/views.py:854 msgid "Etickets" msgstr "Etickets" @@ -3092,15 +3091,15 @@ msgstr "Clubs" msgid "Current club(s) :" msgstr "Clubs actuels : " -#: core/templates/core/user_clubs.jinja:36 +#: core/templates/core/user_clubs.jinja:39 msgid "Old club(s) :" msgstr "Anciens clubs :" -#: core/templates/core/user_clubs.jinja:63 +#: core/templates/core/user_clubs.jinja:69 msgid "Subscribed mailing lists" msgstr "Mailing listes abonnées" -#: core/templates/core/user_clubs.jinja:65 +#: core/templates/core/user_clubs.jinja:71 msgid "Unsubscribe" msgstr "Se désabonner" @@ -3313,7 +3312,7 @@ msgstr "Photos de %(user_name)s" msgid "Preferences" msgstr "Préférences" -#: core/templates/core/user_preferences.jinja:14 trombi/views.py:56 +#: core/templates/core/user_preferences.jinja:14 trombi/views.py:58 msgid "Trombi" msgstr "Trombi" @@ -3362,6 +3361,10 @@ msgstr "Achats" msgid "Product top 10" msgstr "Top 10 produits" +#: core/templates/core/user_stats.jinja:27 counter/views.py:1734 +msgid "Product" +msgstr "Produit" + #: core/templates/core/user_tools.jinja:4 #, python-format msgid "%(user_name)s's tools" @@ -3403,8 +3406,8 @@ msgstr "Cotisations" msgid "Subscription stats" msgstr "Statistiques de cotisation" -#: core/templates/core/user_tools.jinja:29 counter/views.py:792 -#: counter/views.py:1000 +#: core/templates/core/user_tools.jinja:29 counter/views.py:824 +#: counter/views.py:1032 msgid "Counters" msgstr "Comptoirs" @@ -3421,12 +3424,12 @@ msgid "Product types management" msgstr "Gestion des types de produit" #: core/templates/core/user_tools.jinja:35 -#: counter/templates/counter/cash_summary_list.jinja:23 counter/views.py:812 +#: counter/templates/counter/cash_summary_list.jinja:23 counter/views.py:844 msgid "Cash register summaries" msgstr "Relevés de caisse" #: core/templates/core/user_tools.jinja:36 -#: counter/templates/counter/invoices_call.jinja:4 counter/views.py:817 +#: counter/templates/counter/invoices_call.jinja:4 counter/views.py:849 msgid "Invoices call" msgstr "Appels à facture" @@ -3537,101 +3540,101 @@ msgstr "Ajouter un nouveau dossier" msgid "Error creating folder %(folder_name)s: %(msg)s" msgstr "Erreur de création du dossier %(folder_name)s : %(msg)s" -#: core/views/files.py:121 core/views/forms.py:305 core/views/forms.py:312 +#: core/views/files.py:121 core/views/forms.py:303 core/views/forms.py:310 #: sas/views.py:94 #, python-format msgid "Error uploading file %(file_name)s: %(msg)s" msgstr "Erreur d'envoi du fichier %(file_name)s : %(msg)s" -#: core/views/files.py:196 sas/views.py:372 +#: core/views/files.py:196 sas/views.py:378 msgid "Apply rights recursively" msgstr "Appliquer les droits récursivement" -#: core/views/forms.py:87 +#: core/views/forms.py:91 msgid "Heading" msgstr "Titre" -#: core/views/forms.py:88 +#: core/views/forms.py:92 msgid "Italic" msgstr "Italique" -#: core/views/forms.py:89 +#: core/views/forms.py:93 msgid "Bold" msgstr "Gras" -#: core/views/forms.py:90 +#: core/views/forms.py:94 msgid "Strikethrough" msgstr "Barré" -#: core/views/forms.py:91 +#: core/views/forms.py:95 msgid "Underline" msgstr "Souligné" -#: core/views/forms.py:92 +#: core/views/forms.py:96 msgid "Superscript" msgstr "Exposant" -#: core/views/forms.py:93 +#: core/views/forms.py:97 msgid "Subscript" msgstr "Indice" -#: core/views/forms.py:95 +#: core/views/forms.py:99 msgid "Quote" msgstr "Citation" -#: core/views/forms.py:96 +#: core/views/forms.py:100 msgid "Unordered list" msgstr "Liste non ordonnée" -#: core/views/forms.py:97 +#: core/views/forms.py:101 msgid "Ordered list" msgstr "Liste ordonnée" -#: core/views/forms.py:98 +#: core/views/forms.py:102 msgid "Insert image" msgstr "Insérer image" -#: core/views/forms.py:99 +#: core/views/forms.py:103 msgid "Insert link" msgstr "Insérer lien" -#: core/views/forms.py:100 +#: core/views/forms.py:104 msgid "Insert table" msgstr "Insérer tableau" -#: core/views/forms.py:101 +#: core/views/forms.py:105 msgid "Clean block" msgstr "Nettoyer bloc" -#: core/views/forms.py:102 +#: core/views/forms.py:106 msgid "Toggle preview" msgstr "Activer la prévisualisation" -#: core/views/forms.py:103 +#: core/views/forms.py:107 msgid "Toggle side by side" msgstr "Activer la vue côte à côte" -#: core/views/forms.py:104 +#: core/views/forms.py:108 msgid "Toggle fullscreen" msgstr "Activer le plein écran" -#: core/views/forms.py:105 +#: core/views/forms.py:109 msgid "Markdown guide" msgstr "Guide markdown" -#: core/views/forms.py:121 core/views/forms.py:129 +#: core/views/forms.py:123 core/views/forms.py:130 msgid "Choose file" msgstr "Choisir un fichier" -#: core/views/forms.py:145 core/views/forms.py:153 +#: core/views/forms.py:144 core/views/forms.py:151 msgid "Choose user" msgstr "Choisir un utilisateur" -#: core/views/forms.py:185 +#: core/views/forms.py:183 msgid "Username, email, or account number" msgstr "Nom d'utilisateur, email, ou numéro de compte AE" -#: core/views/forms.py:251 +#: core/views/forms.py:249 msgid "" "Profile: you need to be visible on the picture, in order to be recognized (e." "g. by the barmen)" @@ -3639,37 +3642,37 @@ msgstr "" "Photo de profil: vous devez être visible sur la photo afin d'être reconnu " "(par exemple par les barmen)" -#: core/views/forms.py:253 +#: core/views/forms.py:251 msgid "Avatar: used on the forum" msgstr "Avatar : utilisé sur le forum" -#: core/views/forms.py:254 +#: core/views/forms.py:252 msgid "Scrub: let other know how your scrub looks like!" msgstr "Blouse : montrez aux autres à quoi ressemble votre blouse !" -#: core/views/forms.py:316 +#: core/views/forms.py:314 msgid "Bad image format, only jpeg, png, and gif are accepted" msgstr "Mauvais format d'image, seuls les jpeg, png, et gif sont acceptés" -#: core/views/forms.py:336 +#: core/views/forms.py:334 msgid "Godfather" msgstr "Parrain" -#: core/views/forms.py:336 +#: core/views/forms.py:334 msgid "Godchild" msgstr "Fillot" -#: core/views/forms.py:340 counter/views.py:154 trombi/views.py:156 +#: core/views/forms.py:338 counter/views.py:156 trombi/views.py:158 msgid "Select user" msgstr "Choisir un utilisateur" -#: core/views/forms.py:353 core/views/forms.py:371 election/models.py:24 -#: election/views.py:154 +#: core/views/forms.py:351 core/views/forms.py:369 election/models.py:24 +#: election/views.py:155 msgid "edit groups" msgstr "groupe d'édition" -#: core/views/forms.py:356 core/views/forms.py:374 election/models.py:31 -#: election/views.py:157 +#: core/views/forms.py:354 core/views/forms.py:372 election/models.py:31 +#: election/views.py:158 msgid "view groups" msgstr "groupe de vue" @@ -3719,8 +3722,7 @@ msgstr "client" msgid "customers" msgstr "clients" -#: counter/models.py:97 counter/templates/counter/counter_click.jinja:68 -#: counter/templates/counter/counter_click.jinja:102 +#: counter/models.py:97 counter/views.py:377 msgid "Not enough money" msgstr "Solde insuffisant" @@ -3804,11 +3806,11 @@ msgstr "est validé" msgid "refilling" msgstr "rechargement" -#: counter/models.py:441 eboutic/models.py:154 +#: counter/models.py:441 eboutic/models.py:161 msgid "unit price" msgstr "prix unitaire" -#: counter/models.py:442 counter/models.py:739 eboutic/models.py:155 +#: counter/models.py:442 counter/models.py:739 eboutic/models.py:162 msgid "quantity" msgstr "quantité" @@ -3816,8 +3818,8 @@ msgstr "quantité" msgid "Sith account" msgstr "Compte utilisateur" -#: counter/models.py:461 sith/settings.py:371 sith/settings.py:376 -#: sith/settings.py:394 +#: counter/models.py:461 sith/settings.py:372 sith/settings.py:377 +#: sith/settings.py:395 msgid "Credit card" msgstr "Carte bancaire" @@ -3933,11 +3935,11 @@ msgstr "" msgid "counter is not open : no one is connected" msgstr "Le comptoir est fermé" -#: counter/templates/counter/cash_register_summary.jinja:8 +#: counter/templates/counter/cash_register_summary.jinja:14 msgid "Make a cash register summary" msgstr "Faire un relevé de caisse" -#: counter/templates/counter/cash_register_summary.jinja:22 +#: counter/templates/counter/cash_register_summary.jinja:28 msgid "Are you sure ?" msgstr "Êtes vous sûr?" @@ -3950,7 +3952,7 @@ msgstr "Liste des relevés de caisse" msgid "Theoric sums" msgstr "Sommes théoriques" -#: counter/templates/counter/cash_summary_list.jinja:36 counter/views.py:1169 +#: counter/templates/counter/cash_summary_list.jinja:36 counter/views.py:1201 msgid "Emptied" msgstr "Coffre vidé" @@ -3962,17 +3964,17 @@ msgstr "oui" msgid "There is no cash register summary in this website." msgstr "Il n'y a pas de relevé de caisse dans ce site web." -#: counter/templates/counter/counter_click.jinja:36 +#: counter/templates/counter/counter_click.jinja:25 msgid "Add a student card" msgstr "Ajouter une carte étudiante" -#: counter/templates/counter/counter_click.jinja:39 +#: counter/templates/counter/counter_click.jinja:28 msgid "This is not a valid student card UID" msgstr "Ce n'est pas un UID de carte étudiante valide" -#: counter/templates/counter/counter_click.jinja:41 -#: counter/templates/counter/counter_click.jinja:75 -#: counter/templates/counter/counter_click.jinja:123 +#: counter/templates/counter/counter_click.jinja:30 +#: counter/templates/counter/counter_click.jinja:59 +#: counter/templates/counter/counter_click.jinja:113 #: counter/templates/counter/invoices_call.jinja:16 #: launderette/templates/launderette/launderette_admin.jinja:35 #: launderette/templates/launderette/launderette_click.jinja:13 @@ -3981,49 +3983,42 @@ msgstr "Ce n'est pas un UID de carte étudiante valide" msgid "Go" msgstr "Valider" -#: counter/templates/counter/counter_click.jinja:43 +#: counter/templates/counter/counter_click.jinja:32 msgid "Registered cards" msgstr "Cartes enregistrées" -#: counter/templates/counter/counter_click.jinja:51 +#: counter/templates/counter/counter_click.jinja:40 msgid "No card registered" msgstr "Aucune carte enregistrée" -#: counter/templates/counter/counter_click.jinja:55 +#: counter/templates/counter/counter_click.jinja:48 #: launderette/templates/launderette/launderette_admin.jinja:8 msgid "Selling" msgstr "Vente" -#: counter/templates/counter/counter_click.jinja:59 -#: counter/templates/counter/counter_click.jinja:93 -msgid "Too young for that product" -msgstr "Trop jeune pour ce produit" - -#: counter/templates/counter/counter_click.jinja:62 -#: counter/templates/counter/counter_click.jinja:96 -msgid "Not allowed for that product" -msgstr "Non autorisé pour ce produit" - -#: counter/templates/counter/counter_click.jinja:65 -#: counter/templates/counter/counter_click.jinja:99 -msgid "No date of birth provided" -msgstr "Pas de date de naissance renseignée" - -#: counter/templates/counter/counter_click.jinja:77 +#: counter/templates/counter/counter_click.jinja:61 #: eboutic/templates/eboutic/eboutic_main.jinja:27 #: eboutic/templates/eboutic/eboutic_makecommand.jinja:11 msgid "Basket: " msgstr "Panier : " -#: counter/templates/counter/counter_click.jinja:108 +#: counter/templates/counter/counter_click.jinja:98 msgid "Finish" msgstr "Terminer" -#: counter/templates/counter/counter_click.jinja:117 +#: counter/templates/counter/counter_click.jinja:107 #: counter/templates/counter/refilling_list.jinja:9 msgid "Refilling" msgstr "Rechargement" +#: counter/templates/counter/counter_click.jinja:188 counter/views.py:646 +msgid "END" +msgstr "FIN" + +#: counter/templates/counter/counter_click.jinja:188 counter/views.py:648 +msgid "CAN" +msgstr "ANN" + #: counter/templates/counter/counter_list.jinja:4 #: counter/templates/counter/counter_list.jinja:10 msgid "Counter admin list" @@ -4052,37 +4047,37 @@ msgid "There is no counters in this website." msgstr "Il n'y a pas de comptoirs dans ce site web." #: counter/templates/counter/counter_main.jinja:12 -#: counter/templates/counter/counter_main.jinja:16 +#: counter/templates/counter/counter_main.jinja:22 #: launderette/templates/launderette/launderette_click.jinja:8 #, python-format msgid "%(counter_name)s counter" msgstr "Comptoir %(counter_name)s" -#: counter/templates/counter/counter_main.jinja:21 +#: counter/templates/counter/counter_main.jinja:27 msgid "Last selling: " msgstr "Dernière vente : " -#: counter/templates/counter/counter_main.jinja:22 +#: counter/templates/counter/counter_main.jinja:28 msgid "Client: " msgstr "Client : " -#: counter/templates/counter/counter_main.jinja:22 +#: counter/templates/counter/counter_main.jinja:28 msgid "New amount: " msgstr "Nouveau montant : " -#: counter/templates/counter/counter_main.jinja:31 +#: counter/templates/counter/counter_main.jinja:37 msgid "Enter client code:" msgstr "Entrez un code client : " -#: counter/templates/counter/counter_main.jinja:36 +#: counter/templates/counter/counter_main.jinja:42 msgid "validate" msgstr "valider" -#: counter/templates/counter/counter_main.jinja:39 +#: counter/templates/counter/counter_main.jinja:45 msgid "Please, login" msgstr "Merci de vous identifier" -#: counter/templates/counter/counter_main.jinja:44 +#: counter/templates/counter/counter_main.jinja:50 msgid "Barman: " msgstr "Barman : " @@ -4113,7 +4108,7 @@ msgid "CB Payments" msgstr "Payements en Carte Bancaire" #: counter/templates/counter/last_ops.jinja:5 -#: counter/templates/counter/last_ops.jinja:9 +#: counter/templates/counter/last_ops.jinja:15 #, python-format msgid "%(counter_name)s last operations" msgstr "Dernières opérations sur %(counter_name)s" @@ -4186,153 +4181,149 @@ msgstr "Temps" msgid "Top 100 barman %(counter_name)s (all semesters)" msgstr "Top 100 barman %(counter_name)s (tous les semestres)" -#: counter/views.py:118 +#: counter/views.py:120 msgid "This UID is invalid" msgstr "Cet UID est invalide" -#: counter/views.py:176 +#: counter/views.py:178 msgid "User not found" msgstr "Utilisateur non trouvé" -#: counter/views.py:233 +#: counter/views.py:235 msgid "Cash summary" msgstr "Relevé de caisse" -#: counter/views.py:247 +#: counter/views.py:249 msgid "Last operations" msgstr "Dernières opérations" -#: counter/views.py:262 +#: counter/views.py:264 msgid "Take items from stock" msgstr "Prendre des éléments du stock" -#: counter/views.py:315 +#: counter/views.py:317 msgid "Bad credentials" msgstr "Mauvais identifiants" -#: counter/views.py:317 +#: counter/views.py:319 msgid "User is not barman" msgstr "L'utilisateur n'est pas barman." -#: counter/views.py:322 +#: counter/views.py:324 msgid "Bad location, someone is already logged in somewhere else" msgstr "Mauvais comptoir, quelqu'un est déjà connecté ailleurs" -#: counter/views.py:614 -msgid "END" -msgstr "FIN" +#: counter/views.py:368 +msgid "Too young for that product" +msgstr "Trop jeune pour ce produit" -#: counter/views.py:616 -msgid "CAN" -msgstr "ANN" +#: counter/views.py:371 +msgid "Not allowed for that product" +msgstr "Non autorisé pour ce produit" -#: counter/views.py:639 +#: counter/views.py:374 +msgid "No date of birth provided" +msgstr "Pas de date de naissance renseignée" + +#: counter/views.py:671 msgid "You have not enough money to buy all the basket" msgstr "Vous n'avez pas assez d'argent pour acheter le panier" -#: counter/views.py:786 +#: counter/views.py:818 msgid "Counter administration" msgstr "Administration des comptoirs" -#: counter/views.py:788 +#: counter/views.py:820 msgid "Stocks" msgstr "Stocks" -#: counter/views.py:797 -msgid "Products" -msgstr "Produits" - -#: counter/views.py:802 -msgid "Archived products" -msgstr "Produits archivés" - -#: counter/views.py:807 +#: counter/views.py:839 msgid "Product types" msgstr "Types de produit" -#: counter/views.py:986 +#: counter/views.py:1018 msgid "Parent product" msgstr "Produit parent" -#: counter/views.py:992 +#: counter/views.py:1024 msgid "Buying groups" msgstr "Groupes d'achat" -#: counter/views.py:1126 +#: counter/views.py:1158 msgid "10 cents" msgstr "10 centimes" -#: counter/views.py:1127 +#: counter/views.py:1159 msgid "20 cents" msgstr "20 centimes" -#: counter/views.py:1128 +#: counter/views.py:1160 msgid "50 cents" msgstr "50 centimes" -#: counter/views.py:1129 +#: counter/views.py:1161 msgid "1 euro" msgstr "1 €" -#: counter/views.py:1130 +#: counter/views.py:1162 msgid "2 euros" msgstr "2 €" -#: counter/views.py:1131 +#: counter/views.py:1163 msgid "5 euros" msgstr "5 €" -#: counter/views.py:1132 +#: counter/views.py:1164 msgid "10 euros" msgstr "10 €" -#: counter/views.py:1133 +#: counter/views.py:1165 msgid "20 euros" msgstr "20 €" -#: counter/views.py:1134 +#: counter/views.py:1166 msgid "50 euros" msgstr "50 €" -#: counter/views.py:1136 +#: counter/views.py:1168 msgid "100 euros" msgstr "100 €" -#: counter/views.py:1139 counter/views.py:1145 counter/views.py:1151 -#: counter/views.py:1157 counter/views.py:1163 +#: counter/views.py:1171 counter/views.py:1177 counter/views.py:1183 +#: counter/views.py:1189 counter/views.py:1195 msgid "Check amount" msgstr "Montant du chèque" -#: counter/views.py:1142 counter/views.py:1148 counter/views.py:1154 -#: counter/views.py:1160 counter/views.py:1166 +#: counter/views.py:1174 counter/views.py:1180 counter/views.py:1186 +#: counter/views.py:1192 counter/views.py:1198 msgid "Check quantity" msgstr "Nombre de chèque" -#: counter/views.py:1806 +#: counter/views.py:1828 msgid "people(s)" msgstr "personne(s)" -#: eboutic/models.py:94 +#: eboutic/models.py:101 msgid "validated" msgstr "validé" -#: eboutic/models.py:107 +#: eboutic/models.py:114 msgid "Invoice already validated" msgstr "Facture déjà validée" -#: eboutic/models.py:151 +#: eboutic/models.py:158 msgid "product id" msgstr "ID du produit" -#: eboutic/models.py:152 +#: eboutic/models.py:159 msgid "product name" msgstr "nom du produit" -#: eboutic/models.py:153 +#: eboutic/models.py:160 msgid "product type id" msgstr "id du type du produit" -#: eboutic/models.py:170 +#: eboutic/models.py:177 msgid "basket" msgstr "panier" @@ -4346,12 +4337,12 @@ msgstr "Valeur du panier : " msgid "Current account amount: " msgstr "Solde actuel : " -#: eboutic/templates/eboutic/eboutic_main.jinja:41 -#: eboutic/templates/eboutic/eboutic_makecommand.jinja:38 +#: eboutic/templates/eboutic/eboutic_main.jinja:43 +#: eboutic/templates/eboutic/eboutic_makecommand.jinja:40 msgid "Remaining account amount: " msgstr "Solde restant : " -#: eboutic/templates/eboutic/eboutic_main.jinja:48 +#: eboutic/templates/eboutic/eboutic_main.jinja:51 msgid "Proceed to command" msgstr "Procéder à la commande" @@ -4359,18 +4350,18 @@ msgstr "Procéder à la commande" msgid "Basket state" msgstr "État du panier" -#: eboutic/templates/eboutic/eboutic_makecommand.jinja:47 +#: eboutic/templates/eboutic/eboutic_makecommand.jinja:50 msgid "Pay with credit card" msgstr "Payer avec une carte bancaire" -#: eboutic/templates/eboutic/eboutic_makecommand.jinja:52 +#: eboutic/templates/eboutic/eboutic_makecommand.jinja:55 msgid "" "AE account payment disabled because your basket contains refilling items." msgstr "" "Paiement par compte AE désactivé parce que votre panier contient des bons de " "rechargement." -#: eboutic/templates/eboutic/eboutic_makecommand.jinja:57 +#: eboutic/templates/eboutic/eboutic_makecommand.jinja:60 msgid "Pay with Sith account" msgstr "Payer avec un compte AE" @@ -4398,11 +4389,11 @@ msgstr "début des candidatures" msgid "end candidature" msgstr "fin des candidatures" -#: election/models.py:38 election/views.py:160 +#: election/models.py:38 election/views.py:161 msgid "vote groups" msgstr "groupe de vote" -#: election/models.py:45 election/views.py:167 +#: election/models.py:45 election/views.py:168 msgid "candidature groups" msgstr "groupe de candidature" @@ -4466,7 +4457,7 @@ msgstr "Vous avez déjà soumis votre vote." msgid "You have voted in this election." msgstr "Vous avez déjà voté pour cette élection." -#: election/templates/election/election_detail.jinja:266 election/views.py:93 +#: election/templates/election/election_detail.jinja:266 election/views.py:94 msgid "Blank vote" msgstr "Vote blanc" @@ -4535,23 +4526,23 @@ msgstr "au" msgid "Polls open from" msgstr "Votes ouverts du" -#: election/views.py:44 +#: election/views.py:45 msgid "You have selected too much candidates." msgstr "Vous avez sélectionné trop de candidats." -#: election/views.py:60 +#: election/views.py:61 msgid "User to candidate" msgstr "Utilisateur se présentant" -#: election/views.py:118 +#: election/views.py:119 msgid "This role already exists for this election" msgstr "Ce rôle existe déjà pour cette élection" -#: election/views.py:184 +#: election/views.py:174 msgid "Start candidature" msgstr "Début des candidatures" -#: election/views.py:190 +#: election/views.py:176 msgid "End candidature" msgstr "Fin des candidatures" @@ -4699,11 +4690,11 @@ msgstr "Enlever des favoris" msgid "Mark as favorite" msgstr "Ajouter aux favoris" -#: forum/views.py:189 +#: forum/views.py:190 msgid "Apply rights and club owner recursively" msgstr "Appliquer les droits et le club propriétaire récursivement" -#: forum/views.py:407 +#: forum/views.py:410 #, python-format msgid "%(author)s said" msgstr "Citation de %(author)s" @@ -4757,12 +4748,12 @@ msgid "Washing and drying" msgstr "Lavage et séchage" #: launderette/templates/launderette/launderette_book.jinja:27 -#: sith/settings.py:592 +#: sith/settings.py:601 msgid "Washing" msgstr "Lavage" #: launderette/templates/launderette/launderette_book.jinja:31 -#: sith/settings.py:592 +#: sith/settings.py:601 msgid "Drying" msgstr "Séchage" @@ -4971,16 +4962,14 @@ msgid "UV Guide" msgstr "Guide des UVs" #: pedagogy/templates/pedagogy/guide.jinja:34 -#, fuzzy, python-format -#| msgid "display time" +#, python-format msgid "%(display_name)s" -msgstr "temps d'affichage" +msgstr "%(display_name)s" #: pedagogy/templates/pedagogy/guide.jinja:41 -#, fuzzy, python-format -#| msgid "credit type" +#, python-format msgid "%(credit_type)s" -msgstr "type de crédit" +msgstr "%(credit_type)s" #: pedagogy/templates/pedagogy/guide.jinja:59 #: pedagogy/templates/pedagogy/moderation.jinja:12 @@ -5256,368 +5245,380 @@ msgstr "Erreur de création de l'album %(album)s : %(msg)s" msgid "Add user" msgstr "Ajouter une personne" -#: sith/settings.py:219 sith/settings.py:431 +#: sith/settings.py:219 sith/settings.py:432 msgid "English" msgstr "Anglais" -#: sith/settings.py:219 sith/settings.py:430 +#: sith/settings.py:219 sith/settings.py:431 msgid "French" msgstr "Français" -#: sith/settings.py:352 +#: sith/settings.py:353 msgid "TC" msgstr "TC" -#: sith/settings.py:353 +#: sith/settings.py:354 msgid "IMSI" msgstr "IMSI" -#: sith/settings.py:354 +#: sith/settings.py:355 msgid "IMAP" msgstr "IMAP" -#: sith/settings.py:355 +#: sith/settings.py:356 msgid "INFO" msgstr "INFO" -#: sith/settings.py:356 +#: sith/settings.py:357 msgid "GI" msgstr "GI" -#: sith/settings.py:357 sith/settings.py:441 +#: sith/settings.py:358 sith/settings.py:442 msgid "E" msgstr "E" -#: sith/settings.py:358 +#: sith/settings.py:359 msgid "EE" msgstr "EE" -#: sith/settings.py:359 +#: sith/settings.py:360 msgid "GESC" msgstr "GESC" -#: sith/settings.py:360 +#: sith/settings.py:361 msgid "GMC" msgstr "GMC" -#: sith/settings.py:361 +#: sith/settings.py:362 msgid "MC" msgstr "MC" -#: sith/settings.py:362 +#: sith/settings.py:363 msgid "EDIM" msgstr "EDIM" -#: sith/settings.py:363 +#: sith/settings.py:364 msgid "Humanities" msgstr "Humanités" -#: sith/settings.py:364 +#: sith/settings.py:365 msgid "N/A" msgstr "N/A" -#: sith/settings.py:368 sith/settings.py:375 sith/settings.py:392 +#: sith/settings.py:369 sith/settings.py:376 sith/settings.py:393 msgid "Check" msgstr "Chèque" -#: sith/settings.py:369 sith/settings.py:377 sith/settings.py:393 +#: sith/settings.py:370 sith/settings.py:378 sith/settings.py:394 msgid "Cash" msgstr "Espèces" -#: sith/settings.py:370 +#: sith/settings.py:371 msgid "Transfert" msgstr "Virement" -#: sith/settings.py:383 +#: sith/settings.py:384 msgid "Belfort" msgstr "Belfort" -#: sith/settings.py:384 +#: sith/settings.py:385 msgid "Sevenans" msgstr "Sevenans" -#: sith/settings.py:385 +#: sith/settings.py:386 msgid "Montbéliard" msgstr "Montbéliard" -#: sith/settings.py:411 +#: sith/settings.py:412 msgid "Free" msgstr "Libre" -#: sith/settings.py:412 +#: sith/settings.py:413 msgid "CS" msgstr "CS" -#: sith/settings.py:413 +#: sith/settings.py:414 msgid "TM" msgstr "TM" -#: sith/settings.py:414 +#: sith/settings.py:415 msgid "OM" msgstr "OM" -#: sith/settings.py:415 +#: sith/settings.py:416 msgid "QC" msgstr "QC" -#: sith/settings.py:416 +#: sith/settings.py:417 msgid "EC" msgstr "EC" -#: sith/settings.py:417 +#: sith/settings.py:418 msgid "RN" msgstr "RN" -#: sith/settings.py:418 +#: sith/settings.py:419 msgid "ST" msgstr "ST" -#: sith/settings.py:419 +#: sith/settings.py:420 msgid "EXT" msgstr "EXT" -#: sith/settings.py:424 +#: sith/settings.py:425 msgid "Autumn" msgstr "Automne" -#: sith/settings.py:425 +#: sith/settings.py:426 msgid "Spring" msgstr "Printemps" -#: sith/settings.py:426 +#: sith/settings.py:427 msgid "Autumn and spring" msgstr "Automne et printemps" -#: sith/settings.py:432 +#: sith/settings.py:433 msgid "German" msgstr "Allemant" -#: sith/settings.py:433 +#: sith/settings.py:434 msgid "Spanich" msgstr "Espagnol" -#: sith/settings.py:437 +#: sith/settings.py:438 msgid "A" msgstr "A" -#: sith/settings.py:438 +#: sith/settings.py:439 msgid "B" msgstr "B" -#: sith/settings.py:439 +#: sith/settings.py:440 msgid "C" msgstr "C" -#: sith/settings.py:440 +#: sith/settings.py:441 msgid "D" msgstr "D" -#: sith/settings.py:442 +#: sith/settings.py:443 msgid "FX" msgstr "FX" -#: sith/settings.py:443 +#: sith/settings.py:444 msgid "F" msgstr "F" -#: sith/settings.py:444 +#: sith/settings.py:445 msgid "Abs" msgstr "Abs" -#: sith/settings.py:448 +#: sith/settings.py:449 msgid "Selling deletion" msgstr "Suppression de vente" -#: sith/settings.py:449 +#: sith/settings.py:450 msgid "Refilling deletion" msgstr "Suppression de rechargement" -#: sith/settings.py:480 -msgid "One semester" -msgstr "Un semestre, 15 €" - #: sith/settings.py:481 +msgid "One semester" +msgstr "Un semestre, 20 €" + +#: sith/settings.py:482 msgid "Two semesters" -msgstr "Deux semestres, 28 €" +msgstr "Deux semestres, 35 €" -#: sith/settings.py:483 +#: sith/settings.py:484 msgid "Common core cursus" -msgstr "Cursus tronc commun, 45 €" - -#: sith/settings.py:487 -msgid "Branch cursus" -msgstr "Cursus branche, 45 €" +msgstr "Cursus tronc commun, 60 €" #: sith/settings.py:488 +msgid "Branch cursus" +msgstr "Cursus branche, 60 €" + +#: sith/settings.py:489 msgid "Alternating cursus" msgstr "Cursus alternant, 30 €" -#: sith/settings.py:489 +#: sith/settings.py:490 msgid "Honorary member" msgstr "Membre honoraire, 0 €" -#: sith/settings.py:490 +#: sith/settings.py:491 msgid "Assidu member" msgstr "Membre d'Assidu, 0 €" -#: sith/settings.py:491 +#: sith/settings.py:492 msgid "Amicale/DOCEO member" msgstr "Membre de l'Amicale/DOCEO, 0 €" -#: sith/settings.py:492 +#: sith/settings.py:493 msgid "UT network member" msgstr "Cotisant du réseau UT, 0 €" -#: sith/settings.py:493 +#: sith/settings.py:494 msgid "CROUS member" msgstr "Membres du CROUS, 0 €" -#: sith/settings.py:494 +#: sith/settings.py:495 msgid "Sbarro/ESTA member" -msgstr "Membre de Sbarro ou de l'ESTA, 15 €" +msgstr "Membre de Sbarro ou de l'ESTA, 20 €" -#: sith/settings.py:496 +#: sith/settings.py:497 msgid "One semester Welcome Week" msgstr "Un semestre Welcome Week" -#: sith/settings.py:500 +#: sith/settings.py:501 +msgid "One month for free" +msgstr "Un mois gratuit" + +#: sith/settings.py:502 msgid "Two months for free" msgstr "Deux mois gratuits" -#: sith/settings.py:501 +#: sith/settings.py:503 msgid "Eurok's volunteer" msgstr "Bénévole Eurockéennes" -#: sith/settings.py:503 +#: sith/settings.py:505 msgid "Six weeks for free" msgstr "6 semaines gratuites" -#: sith/settings.py:507 +#: sith/settings.py:509 msgid "One day" msgstr "Un jour" #: sith/settings.py:510 +msgid "GA staff member" +msgstr "Membre staff GA (2 semaines), 1 €" + +#: sith/settings.py:513 msgid "One semester (-20%)" msgstr "Un semestre (-20%), 12 €" -#: sith/settings.py:515 +#: sith/settings.py:518 msgid "Two semesters (-20%)" msgstr "Deux semestres (-20%), 22 €" -#: sith/settings.py:520 +#: sith/settings.py:523 msgid "Common core cursus (-20%)" msgstr "Cursus tronc commun (-20%), 36 €" -#: sith/settings.py:525 +#: sith/settings.py:528 msgid "Branch cursus (-20%)" msgstr "Cursus branche (-20%), 36 €" -#: sith/settings.py:530 +#: sith/settings.py:533 msgid "Alternating cursus (-20%)" msgstr "Cursus alternant (-20%), 24 €" -#: sith/settings.py:552 +#: sith/settings.py:539 +msgid "One year for free(CA offer)" +msgstr "Une année offerte (Offre CA)" + +#: sith/settings.py:561 msgid "President" msgstr "Président" -#: sith/settings.py:553 +#: sith/settings.py:562 msgid "Vice-President" msgstr "Vice-Président" -#: sith/settings.py:554 +#: sith/settings.py:563 msgid "Treasurer" msgstr "Trésorier" -#: sith/settings.py:555 +#: sith/settings.py:564 msgid "Communication supervisor" msgstr "Responsable communication" -#: sith/settings.py:556 +#: sith/settings.py:565 msgid "Secretary" msgstr "Secrétaire" -#: sith/settings.py:557 +#: sith/settings.py:566 msgid "IT supervisor" msgstr "Responsable info" -#: sith/settings.py:558 +#: sith/settings.py:567 msgid "Board member" msgstr "Membre du bureau" -#: sith/settings.py:559 +#: sith/settings.py:568 msgid "Active member" msgstr "Membre actif" -#: sith/settings.py:560 +#: sith/settings.py:569 msgid "Curious" msgstr "Curieux" -#: sith/settings.py:596 +#: sith/settings.py:605 msgid "A new poster needs to be moderated" msgstr "Une nouvelle affiche a besoin d'être modérée" -#: sith/settings.py:597 +#: sith/settings.py:606 msgid "A new mailing list needs to be moderated" msgstr "Une nouvelle mailing list a besoin d'être modérée" -#: sith/settings.py:600 +#: sith/settings.py:609 msgid "A new pedagogy comment has been signaled for moderation" msgstr "" "Un nouveau commentaire de la pédagogie a été signalé pour la modération" -#: sith/settings.py:602 +#: sith/settings.py:611 #, python-format msgid "There are %s fresh news to be moderated" msgstr "Il y a %s nouvelles toutes fraîches à modérer" -#: sith/settings.py:603 +#: sith/settings.py:612 msgid "New files to be moderated" msgstr "Nouveaux fichiers à modérer" -#: sith/settings.py:604 +#: sith/settings.py:613 #, python-format msgid "There are %s pictures to be moderated in the SAS" msgstr "Il y a %s photos à modérer dans le SAS" -#: sith/settings.py:605 +#: sith/settings.py:614 msgid "You've been identified on some pictures" msgstr "Vous avez été identifié sur des photos" -#: sith/settings.py:606 +#: sith/settings.py:615 #, python-format msgid "You just refilled of %s €" msgstr "Vous avez rechargé votre compte de %s€" -#: sith/settings.py:607 +#: sith/settings.py:616 #, python-format msgid "You just bought %s" msgstr "Vous avez acheté %s" -#: sith/settings.py:608 +#: sith/settings.py:617 msgid "You have a notification" msgstr "Vous avez une notification" -#: sith/settings.py:620 +#: sith/settings.py:629 msgid "Success!" msgstr "Succès !" -#: sith/settings.py:621 +#: sith/settings.py:630 msgid "Fail!" msgstr "Échec !" -#: sith/settings.py:622 +#: sith/settings.py:631 msgid "You successfully posted an article in the Weekmail" msgstr "Article posté avec succès dans le Weekmail" -#: sith/settings.py:623 +#: sith/settings.py:632 msgid "You successfully edited an article in the Weekmail" msgstr "Article édité avec succès dans le Weekmail" -#: sith/settings.py:624 +#: sith/settings.py:633 msgid "You successfully sent the Weekmail" msgstr "Weekmail envoyé avec succès" -#: sith/settings.py:632 +#: sith/settings.py:641 msgid "AE tee-shirt" msgstr "Tee-shirt AE" @@ -5653,23 +5654,23 @@ msgstr "" msgid "todo" msgstr "à faire" -#: stock/models.py:128 +#: stock/models.py:127 msgid "shopping lists" msgstr "listes de courses" -#: stock/models.py:144 +#: stock/models.py:143 msgid "quantity to buy" msgstr "quantité à acheter" -#: stock/models.py:146 +#: stock/models.py:145 msgid "quantity to buy during the next shopping session" msgstr "quantité à acheter pendant les prochaines courses" -#: stock/models.py:149 +#: stock/models.py:148 msgid "quantity bought" msgstr "quantité achetée" -#: stock/models.py:151 +#: stock/models.py:150 msgid "quantity bought during the last shopping session" msgstr "quantité achetée pendant les dernières courses" @@ -5860,11 +5861,11 @@ msgid "Eboutic is reserved to specific users. In doubt, don't use it." msgstr "" "Eboutic est réservé à des cas particuliers. Dans le doute, ne l'utilisez pas." -#: subscription/views.py:101 +#: subscription/views.py:96 msgid "A user with that email address already exists" msgstr "Un utilisateur avec cette adresse email existe déjà" -#: subscription/views.py:124 +#: subscription/views.py:119 msgid "You must either choose an existing user or create a new one properly" msgstr "" "Vous devez soit choisir un utilisateur existant, soit en créer un proprement" @@ -5990,6 +5991,10 @@ msgstr "Fin des commentaires : " msgid "Export" msgstr "Exporter" +#: trombi/templates/trombi/detail.jinja:36 +msgid "Add club membership" +msgstr "Ajouter appartenance à un club" + #: trombi/templates/trombi/edit_profile.jinja:4 #: trombi/templates/trombi/edit_profile.jinja:8 msgid "Edit profile" @@ -6080,27 +6085,27 @@ msgstr "" msgid "Edit comment" msgstr "Éditer le commentaire" -#: trombi/views.py:68 +#: trombi/views.py:70 msgid "My profile" msgstr "Mon profil" -#: trombi/views.py:75 +#: trombi/views.py:77 msgid "My pictures" msgstr "Mes photos" -#: trombi/views.py:87 +#: trombi/views.py:89 msgid "Admin tools" msgstr "Admin Trombi" -#: trombi/views.py:220 +#: trombi/views.py:222 msgid "Explain why you rejected the comment" msgstr "Expliquez pourquoi vous refusez le commentaire" -#: trombi/views.py:253 +#: trombi/views.py:255 msgid "Rejected comment" msgstr "Commentaire rejeté" -#: trombi/views.py:255 +#: trombi/views.py:257 #, python-format msgid "" "Your comment to %(target)s on the Trombi \"%(trombi)s\" was rejected for the " @@ -6117,16 +6122,16 @@ msgstr "" "\n" "%(content)s" -#: trombi/views.py:287 +#: trombi/views.py:289 #, python-format msgid "%(name)s (deadline: %(date)s)" msgstr "%(name)s (date limite: %(date)s)" -#: trombi/views.py:297 +#: trombi/views.py:299 msgid "Select trombi" msgstr "Choisir un trombi" -#: trombi/views.py:299 +#: trombi/views.py:301 msgid "" "This allows you to subscribe to a Trombi. Be aware that you can subscribe " "only once, so don't play with that, or you will expose yourself to the " @@ -6136,19 +6141,19 @@ msgstr "" "pouvez vous inscrire qu'à un seul Trombi, donc ne jouez pas avec cet option " "ou vous encourerez la colère des admins!" -#: trombi/views.py:372 +#: trombi/views.py:374 msgid "Personal email (not UTBM)" msgstr "Email personnel (pas UTBM)" -#: trombi/views.py:373 +#: trombi/views.py:375 msgid "Phone" msgstr "Téléphone" -#: trombi/views.py:374 +#: trombi/views.py:376 msgid "Native town" msgstr "Ville d'origine" -#: trombi/views.py:458 +#: trombi/views.py:489 msgid "" "You can not yet write comment, you must wait for the subscription deadline " "to be passed." @@ -6156,23 +6161,11 @@ msgstr "" "Vous ne pouvez pas encore écrire de commentaires, vous devez attendre la fin " "des inscriptions" -#: trombi/views.py:465 +#: trombi/views.py:496 msgid "You can not write comment anymore, the deadline is already passed." msgstr "Vous ne pouvez plus écrire de commentaires, la date est passée." -#: trombi/views.py:478 +#: trombi/views.py:509 #, python-format msgid "Maximum characters: %(max_length)s" msgstr "Nombre de caractères max: %(max_length)s" - -#~ msgid "ENERGIE" -#~ msgstr "ENERGIE" - -#~ msgid "HUMA" -#~ msgstr "HUMA" - -#~ msgid "Former website" -#~ msgstr "Ancien site" - -#~ msgid "Help on the syntax" -#~ msgstr "Aide sur la syntaxe" diff --git a/rootplace/management/commands/delete_all_forum_user_messages.py b/rootplace/management/commands/delete_all_forum_user_messages.py index 3d6b4a22..8292d919 100644 --- a/rootplace/management/commands/delete_all_forum_user_messages.py +++ b/rootplace/management/commands/delete_all_forum_user_messages.py @@ -31,7 +31,7 @@ from rootplace.views import delete_all_forum_user_messages class Command(BaseCommand): """ - Delete all forum messages from a user + Delete all forum messages from a user """ help = "Delete all user's forum message" diff --git a/rootplace/views.py b/rootplace/views.py index 460250cb..6ec44549 100644 --- a/rootplace/views.py +++ b/rootplace/views.py @@ -94,10 +94,10 @@ def merge_users(u1, u2): def delete_all_forum_user_messages(user, moderator, verbose=False): """ - Create a ForumMessageMeta that says a forum - message is deleted on every forum message of an user - user: the user to delete messages from - moderator: the one marked as the moderator + Create a ForumMessageMeta that says a forum + message is deleted on every forum message of an user + user: the user to delete messages from + moderator: the one marked as the moderator """ for message in user.forum_messages.all(): if message.is_deleted(): @@ -145,9 +145,9 @@ class MergeUsersView(FormView): class DeleteAllForumUserMessagesView(FormView): """ - Delete all forum messages from an user - Messages are soft deleted and are still visible from admins - GUI frontend to the dedicated command + Delete all forum messages from an user + Messages are soft deleted and are still visible from admins + GUI frontend to the dedicated command """ template_name = "rootplace/delete_user_messages.jinja" diff --git a/sith/settings.py b/sith/settings.py index fa2cb37e..29e7783f 100644 --- a/sith/settings.py +++ b/sith/settings.py @@ -280,7 +280,8 @@ SITH_NAME = "Sith website" SITH_TWITTER = "@ae_utbm" # AE configuration -SITH_MAIN_CLUB_ID = 1 # TODO: keep only that first setting, with the ID, and do the same for the other clubs +# TODO: keep only that first setting, with the ID, and do the same for the other clubs +SITH_MAIN_CLUB_ID = 1 SITH_MAIN_CLUB = { "name": "AE", "unix_name": "ae", @@ -477,14 +478,14 @@ SITH_SUBSCRIPTION_END = 10 # Subscription durations are in semestres # Be careful, modifying this parameter will need a migration to be applied SITH_SUBSCRIPTIONS = { - "un-semestre": {"name": _("One semester"), "price": 15, "duration": 1}, - "deux-semestres": {"name": _("Two semesters"), "price": 28, "duration": 2}, + "un-semestre": {"name": _("One semester"), "price": 20, "duration": 1}, + "deux-semestres": {"name": _("Two semesters"), "price": 35, "duration": 2}, "cursus-tronc-commun": { "name": _("Common core cursus"), - "price": 45, + "price": 60, "duration": 4, }, - "cursus-branche": {"name": _("Branch cursus"), "price": 45, "duration": 6}, + "cursus-branche": {"name": _("Branch cursus"), "price": 60, "duration": 6}, "cursus-alternant": {"name": _("Alternating cursus"), "price": 30, "duration": 6}, "membre-honoraire": {"name": _("Honorary member"), "price": 0, "duration": 666}, "assidu": {"name": _("Assidu member"), "price": 0, "duration": 2}, @@ -497,6 +498,7 @@ SITH_SUBSCRIPTIONS = { "price": 0, "duration": 1, }, + "un-mois-essai": {"name": _("One month for free"), "price": 0, "duration": 0.166}, "deux-mois-essai": {"name": _("Two months for free"), "price": 0, "duration": 0.33}, "benevoles-euroks": {"name": _("Eurok's volunteer"), "price": 5, "duration": 0.1}, "six-semaines-essai": { @@ -505,6 +507,7 @@ SITH_SUBSCRIPTIONS = { "duration": 0.23, }, "un-jour": {"name": _("One day"), "price": 0, "duration": 0.00555333}, + "membre-staff-ga": {"name": _("GA staff member"), "price": 1, "duration": 0.076}, # Discount subscriptions "un-semestre-reduction": { "name": _("One semester (-20%)"), @@ -530,6 +533,12 @@ SITH_SUBSCRIPTIONS = { "name": _("Alternating cursus (-20%)"), "price": 24, "duration": 6, + }, + # CA special offer + "un-an-offert-CA": { + "name": _("One year for free(CA offer)"), + "price": 0, + "duration": 2, } # To be completed.... } @@ -665,3 +674,17 @@ if "test" in sys.argv: if SENTRY_DSN: # Connection to sentry sentry_sdk.init(dsn=SENTRY_DSN, integrations=[DjangoIntegration()]) + + +SITH_FRONT_DEP_VERSIONS = { + "https://github.com/chartjs/Chart.js/": "2.6.0", + "https://github.com/xdan/datetimepicker/": "2.5.21", + "https://github.com/Ionaru/easy-markdown-editor/": "2.7.0", + "https://github.com/FortAwesome/Font-Awesome/": "4.7.0", + "https://github.com/jquery/jquery/": "3.1.0", + "https://github.com/sethmcl/jquery-ui/": "1.11.1", + "https://github.com/viralpatel/jquery.shorten/": "", + "https://github.com/getsentry/sentry-javascript/": "4.0.6", + "https://github.com/jhuckaby/webcamjs/": "1.0.0", + "https://github.com/vuejs/vue-next": "3.2.18", +} diff --git a/sith/toolbar_debug.py b/sith/toolbar_debug.py index 03b531d5..139aec36 100644 --- a/sith/toolbar_debug.py +++ b/sith/toolbar_debug.py @@ -1,7 +1,8 @@ # -*- coding:utf-8 -* # -# Copyright 2016,2017 +# Copyright 2016,2017,2021 # - Sli +# - Skia # # Ce fichier fait partie du site de l'Association des Étudiants de l'UTBM, # http://ae.utbm.fr. @@ -27,7 +28,10 @@ from debug_toolbar.panels.templates import TemplatesPanel as BaseTemplatesPanel class TemplatesPanel(BaseTemplatesPanel): def generate_stats(self, *args): - template = self.templates[0]["template"] - if not hasattr(template, "engine") and hasattr(template, "backend"): - template.engine = template.backend + try: + template = self.templates[0]["template"] + if not hasattr(template, "engine") and hasattr(template, "backend"): + template.engine = template.backend + except IndexError: # No template + pass return super().generate_stats(*args) diff --git a/stock/models.py b/stock/models.py index f23ba277..f8696233 100644 --- a/stock/models.py +++ b/stock/models.py @@ -120,8 +120,7 @@ class ShoppingList(models.Model): class ShoppingListItem(models.Model): - """ - """ + """""" shopping_lists = models.ManyToManyField( ShoppingList, diff --git a/subscription/migrations/0012_auto_20200615_1438.py b/subscription/migrations/0012_auto_20200615_1438.py new file mode 100644 index 00000000..b318b00f --- /dev/null +++ b/subscription/migrations/0012_auto_20200615_1438.py @@ -0,0 +1,45 @@ +# Generated by Django 2.2.13 on 2020-06-15 12:38 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("subscription", "0011_auto_20190825_2215"), + ] + + operations = [ + migrations.AlterField( + model_name="subscription", + name="subscription_type", + field=models.CharField( + choices=[ + ("amicale/doceo", "Amicale/DOCEO member"), + ("assidu", "Assidu member"), + ("benevoles-euroks", "Eurok's volunteer"), + ("crous", "CROUS member"), + ("cursus-alternant", "Alternating cursus"), + ("cursus-alternant-reduction", "Alternating cursus (-20%)"), + ("cursus-branche", "Branch cursus"), + ("cursus-branche-reduction", "Branch cursus (-20%)"), + ("cursus-tronc-commun", "Common core cursus"), + ("cursus-tronc-commun-reduction", "Common core cursus (-20%)"), + ("deux-mois-essai", "Two months for free"), + ("deux-semestres", "Two semesters"), + ("deux-semestres-reduction", "Two semesters (-20%)"), + ("membre-honoraire", "Honorary member"), + ("membre-staff-ga", "GA staff member"), + ("reseau-ut", "UT network member"), + ("sbarro/esta", "Sbarro/ESTA member"), + ("six-semaines-essai", "Six weeks for free"), + ("un-jour", "One day"), + ("un-semestre", "One semester"), + ("un-semestre-reduction", "One semester (-20%)"), + ("un-semestre-welcome", "One semester Welcome Week"), + ], + max_length=255, + verbose_name="subscription type", + ), + ), + ] diff --git a/subscription/migrations/0013_auto_20200828_2117.py b/subscription/migrations/0013_auto_20200828_2117.py new file mode 100644 index 00000000..7f5b4091 --- /dev/null +++ b/subscription/migrations/0013_auto_20200828_2117.py @@ -0,0 +1,46 @@ +# Generated by Django 2.2.13 on 2020-08-28 19:17 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("subscription", "0012_auto_20200615_1438"), + ] + + operations = [ + migrations.AlterField( + model_name="subscription", + name="subscription_type", + field=models.CharField( + choices=[ + ("amicale/doceo", "Amicale/DOCEO member"), + ("assidu", "Assidu member"), + ("benevoles-euroks", "Eurok's volunteer"), + ("crous", "CROUS member"), + ("cursus-alternant", "Alternating cursus"), + ("cursus-alternant-reduction", "Alternating cursus (-20%)"), + ("cursus-branche", "Branch cursus"), + ("cursus-branche-reduction", "Branch cursus (-20%)"), + ("cursus-tronc-commun", "Common core cursus"), + ("cursus-tronc-commun-reduction", "Common core cursus (-20%)"), + ("deux-mois-essai", "Two months for free"), + ("deux-semestres", "Two semesters"), + ("deux-semestres-reduction", "Two semesters (-20%)"), + ("membre-honoraire", "Honorary member"), + ("membre-staff-ga", "GA staff member"), + ("reseau-ut", "UT network member"), + ("sbarro/esta", "Sbarro/ESTA member"), + ("six-semaines-essai", "Six weeks for free"), + ("un-jour", "One day"), + ("un-mois-essai", "One month for free"), + ("un-semestre", "One semester"), + ("un-semestre-reduction", "One semester (-20%)"), + ("un-semestre-welcome", "One semester Welcome Week"), + ], + max_length=255, + verbose_name="subscription type", + ), + ), + ] diff --git a/subscription/migrations/0014_auto_20201207_2323.py b/subscription/migrations/0014_auto_20201207_2323.py new file mode 100644 index 00000000..71cf3f02 --- /dev/null +++ b/subscription/migrations/0014_auto_20201207_2323.py @@ -0,0 +1,47 @@ +# Generated by Django 2.2.17 on 2020-12-07 22:23 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("subscription", "0013_auto_20200828_2117"), + ] + + operations = [ + migrations.AlterField( + model_name="subscription", + name="subscription_type", + field=models.CharField( + choices=[ + ("amicale/doceo", "Amicale/DOCEO member"), + ("assidu", "Assidu member"), + ("benevoles-euroks", "Eurok's volunteer"), + ("crous", "CROUS member"), + ("cursus-alternant", "Alternating cursus"), + ("cursus-alternant-reduction", "Alternating cursus (-20%)"), + ("cursus-branche", "Branch cursus"), + ("cursus-branche-reduction", "Branch cursus (-20%)"), + ("cursus-tronc-commun", "Common core cursus"), + ("cursus-tronc-commun-reduction", "Common core cursus (-20%)"), + ("deux-mois-essai", "Two months for free"), + ("deux-semestres", "Two semesters"), + ("deux-semestres-reduction", "Two semesters (-20%)"), + ("membre-honoraire", "Honorary member"), + ("membre-staff-ga", "GA staff member"), + ("reseau-ut", "UT network member"), + ("sbarro/esta", "Sbarro/ESTA member"), + ("six-semaines-essai", "Six weeks for free"), + ("un-an-offert-CA", "One year for free(CA offer)"), + ("un-jour", "One day"), + ("un-mois-essai", "One month for free"), + ("un-semestre", "One semester"), + ("un-semestre-reduction", "One semester (-20%)"), + ("un-semestre-welcome", "One semester Welcome Week"), + ], + max_length=255, + verbose_name="subscription type", + ), + ), + ] diff --git a/subscription/tests.py b/subscription/tests.py index 895e6596..5a98b71e 100644 --- a/subscription/tests.py +++ b/subscription/tests.py @@ -114,6 +114,18 @@ class SubscriptionIntegrationTest(TestCase): call_command("populate") self.user = User.objects.filter(username="public").first() + def test_duration_one_month(self): + + s = Subscription( + member=User.objects.filter(pk=self.user.pk).first(), + subscription_type=list(settings.SITH_SUBSCRIPTIONS.keys())[3], + payment_method=settings.SITH_SUBSCRIPTION_PAYMENT_METHOD[0], + ) + s.subscription_start = date(2017, 8, 29) + s.subscription_end = s.compute_end(duration=0.166, start=s.subscription_start) + s.save() + self.assertTrue(s.subscription_end == date(2017, 9, 29)) + def test_duration_two_months(self): s = Subscription( @@ -122,11 +134,11 @@ class SubscriptionIntegrationTest(TestCase): payment_method=settings.SITH_SUBSCRIPTION_PAYMENT_METHOD[0], ) s.subscription_start = date(2017, 8, 29) - s.subscription_end = s.compute_end(duration=0.33, start=s.subscription_start) + s.subscription_end = s.compute_end(duration=0.333, start=s.subscription_start) s.save() self.assertTrue(s.subscription_end == date(2017, 10, 29)) - def test_duration_two_months(self): + def test_duration_one_day(self): s = Subscription( member=User.objects.filter(pk=self.user.pk).first(), diff --git a/subscription/views.py b/subscription/views.py index 45e04a55..63ce0a33 100644 --- a/subscription/views.py +++ b/subscription/views.py @@ -36,22 +36,17 @@ from subscription.models import Subscription from core.views.forms import SelectDateTime from core.models import User from core.views.forms import SelectDate +from core.views.forms import TzAwareDateTimeField class SelectionDateForm(forms.Form): def __init__(self, *args, **kwargs): super(SelectionDateForm, self).__init__(*args, **kwargs) - self.fields["start_date"] = forms.DateTimeField( - input_formats=["%Y-%m-%d %H:%M:%S"], - label=_("Start date"), - widget=SelectDateTime, - required=True, + self.fields["start_date"] = TzAwareDateTimeField( + label=_("Start date"), required=True ) - self.fields["end_date"] = forms.DateTimeField( - input_formats=["%Y-%m-%d %H:%M:%S"], - label=_("End date"), - widget=SelectDateTime, - required=True, + self.fields["end_date"] = TzAwareDateTimeField( + label=_("End date"), required=True ) diff --git a/trombi/templates/trombi/detail.jinja b/trombi/templates/trombi/detail.jinja index de788abb..85556703 100644 --- a/trombi/templates/trombi/detail.jinja +++ b/trombi/templates/trombi/detail.jinja @@ -33,6 +33,7 @@

  • {{ u.user.get_display_name() }}
    +
    {% endfor %}
    diff --git a/trombi/urls.py b/trombi/urls.py index 76575ef9..9858ea65 100644 --- a/trombi/urls.py +++ b/trombi/urls.py @@ -1,7 +1,8 @@ # -*- coding:utf-8 -* # -# Copyright 2017 +# Copyright 2017,2020 # - Skia +# - Sli # # Ce fichier fait partie du site de l'Association des Étudiants de l'UTBM, # http://ae.utbm.fr. @@ -81,4 +82,9 @@ urlpatterns = [ UserTrombiDeleteMembershipView.as_view(), name="delete_membership", ), + re_path( + r"^membership/(?P[0-9]+)/create$", + UserTrombiAddMembershipView.as_view(), + name="create_membership", + ), ] diff --git a/trombi/views.py b/trombi/views.py index 2f21a68d..71749f78 100644 --- a/trombi/views.py +++ b/trombi/views.py @@ -1,7 +1,8 @@ # -*- coding:utf-8 -* # -# Copyright 2017 +# Copyright 2017,2020 # - Skia +# - Sli # # Ce fichier fait partie du site de l'Association des Étudiants de l'UTBM, # http://ae.utbm.fr. @@ -31,6 +32,7 @@ from django.utils.translation import ugettext_lazy as _ from django import forms from django.conf import settings from django.forms.models import modelform_factory +from django.core.exceptions import PermissionDenied from ajax_select.fields import AutoCompleteSelectField @@ -410,6 +412,35 @@ class UserTrombiDeleteMembershipView(TrombiTabsMixin, CanEditMixin, DeleteView): ) +# Used by admins when someone does not have every club in his list +class UserTrombiAddMembershipView(TrombiTabsMixin, CreateView): + model = TrombiClubMembership + template_name = "core/edit.jinja" + fields = ["club", "role", "start", "end"] + pk_url_kwarg = "user_id" + current_tab = "profile" + + def dispatch(self, request, *arg, **kwargs): + self.trombi_user = get_object_or_404(TrombiUser, pk=kwargs["user_id"]) + if not self.trombi_user.trombi.is_owned_by(request.user): + raise PermissionDenied() + + return super(UserTrombiAddMembershipView, self).dispatch( + request, *arg, **kwargs + ) + + def form_valid(self, form): + membership = form.save(commit=False) + membership.user = self.trombi_user + membership.save() + return HttpResponseRedirect(self.get_success_url()) + + def get_success_url(self): + return reverse( + "trombi:detail", kwargs={"trombi_id": self.trombi_user.trombi.id} + ) + + class UserTrombiEditMembershipView(CanEditMixin, TrombiTabsMixin, UpdateView): model = TrombiClubMembership pk_url_kwarg = "membership_id"