diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 33ce0cd8..8e3ec20a 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -7,25 +7,10 @@ stages: variables: GIT_SUBMODULE_STRATEGY: recursive -# Debian Buster -# py37-django22: -# stage: test -# image: debian:buster-backports -# before_script: -# - > -# apt-get update && -# apt-get install --no-install-recommends -t buster-backports -y -# python3-django python3-django-crispy-forms -# python3-django-extensions python3-django-filters python3-django-polymorphic -# python3-djangorestframework python3-django-oauth-toolkit python3-psycopg2 python3-pil -# python3-babel python3-lockfile python3-pip python3-phonenumbers python3-memcache -# python3-bs4 python3-setuptools tox texlive-xetex -# script: tox -e py37-django22 - -# Ubuntu 20.04 -py38-django22: +# Ubuntu 22.04 +py310-django50: stage: test - image: ubuntu:20.04 + image: ubuntu:22.04 before_script: # Fix tzdata prompt - ln -sf /usr/share/zoneinfo/Europe/Paris /etc/localtime && echo Europe/Paris > /etc/timezone @@ -37,12 +22,12 @@ py38-django22: python3-djangorestframework python3-django-oauth-toolkit python3-psycopg2 python3-pil python3-babel python3-lockfile python3-pip python3-phonenumbers python3-memcache python3-bs4 python3-setuptools tox texlive-xetex - script: tox -e py38-django22 + script: tox -e py310-django50 -# Debian Bullseye -py39-django22: +# Debian Bookworm +py311-django50: stage: test - image: debian:bullseye + image: debian:bookworm before_script: - > apt-get update && @@ -52,7 +37,7 @@ py39-django22: python3-djangorestframework python3-django-oauth-toolkit python3-psycopg2 python3-pil python3-babel python3-lockfile python3-pip python3-phonenumbers python3-memcache python3-bs4 python3-setuptools tox texlive-xetex - script: tox -e py39-django22 + script: tox -e py311-django50 linters: stage: quality-assurance diff --git a/apps/activity/forms.py b/apps/activity/forms.py index 6e1c35ff..c7733d8c 100644 --- a/apps/activity/forms.py +++ b/apps/activity/forms.py @@ -1,6 +1,8 @@ # Copyright (C) 2018-2024 by BDE ENS Paris-Saclay # SPDX-License-Identifier: GPL-3.0-or-later +from bootstrap_datepicker_plus.widgets import DateTimePickerInput + from datetime import timedelta from random import shuffle @@ -10,7 +12,7 @@ from django.utils import timezone from django.utils.translation import gettext_lazy as _ from member.models import Club from note.models import Note, NoteUser -from note_kfet.inputs import Autocomplete, DateTimePickerInput +from note_kfet.inputs import Autocomplete from note_kfet.middlewares import get_current_request from permission.backends import PermissionBackend diff --git a/apps/api/urls.py b/apps/api/urls.py index 7c73093b..d328ae97 100644 --- a/apps/api/urls.py +++ b/apps/api/urls.py @@ -2,7 +2,7 @@ # SPDX-License-Identifier: GPL-3.0-or-later from django.conf import settings -from django.conf.urls import url, include +from django.urls import include, re_path from rest_framework import routers from .views import UserInformationView @@ -47,7 +47,7 @@ app_name = 'api' # Wire up our API using automatic URL routing. # Additionally, we include login URLs for the browsable API. urlpatterns = [ - url('^', include(router.urls)), - url('^me/', UserInformationView.as_view()), - url('^api-auth/', include('rest_framework.urls', namespace='rest_framework')), + re_path('^', include(router.urls)), + re_path('^me/', UserInformationView.as_view()), + re_path('^api-auth/', include('rest_framework.urls', namespace='rest_framework')), ] diff --git a/apps/member/forms.py b/apps/member/forms.py index 3d892705..bd5d4065 100644 --- a/apps/member/forms.py +++ b/apps/member/forms.py @@ -3,6 +3,7 @@ import io +from bootstrap_datepicker_plus.widgets import DatePickerInput from PIL import Image, ImageSequence from django import forms from django.conf import settings @@ -13,7 +14,7 @@ from django.forms import CheckboxSelectMultiple from django.utils import timezone from django.utils.translation import gettext_lazy as _ from note.models import NoteSpecial, Alias -from note_kfet.inputs import Autocomplete, AmountInput, DatePickerInput +from note_kfet.inputs import Autocomplete, AmountInput from permission.models import PermissionMask, Role from .models import Profile, Club, Membership @@ -32,7 +33,7 @@ class UserForm(forms.ModelForm): # Django usernames can only contain letters, numbers, @, ., +, - and _. # We want to allow users to have uncommon and unpractical usernames: # That is their problem, and we have normalized aliases for us. - return super()._get_validation_exclusions() + ["username"] + return super()._get_validation_exclusions() | {"username"} class Meta: model = User diff --git a/apps/member/tests/test_login.py b/apps/member/tests/test_login.py index b8873a14..ce5de1cf 100644 --- a/apps/member/tests/test_login.py +++ b/apps/member/tests/test_login.py @@ -44,7 +44,7 @@ class TemplateLoggedInTests(TestCase): self.assertRedirects(response, settings.LOGIN_REDIRECT_URL, 302, 302) def test_logout(self): - response = self.client.get(reverse("logout")) + response = self.client.post(reverse("logout")) self.assertEqual(response.status_code, 200) def test_admin_index(self): diff --git a/apps/note/api/urls.py b/apps/note/api/urls.py index 0522ebea..349348da 100644 --- a/apps/note/api/urls.py +++ b/apps/note/api/urls.py @@ -13,7 +13,7 @@ def register_note_urls(router, path): router.register(path + '/note', NotePolymorphicViewSet) router.register(path + '/alias', AliasViewSet) router.register(path + '/trust', TrustViewSet) - router.register(path + '/consumer', ConsumerViewSet) + router.register(path + '/consumer', ConsumerViewSet, basename="consumer") router.register(path + '/transaction/category', TemplateCategoryViewSet) router.register(path + '/transaction/transaction', TransactionViewSet) diff --git a/apps/note/api/views.py b/apps/note/api/views.py index 0aba9adc..c70d3e97 100644 --- a/apps/note/api/views.py +++ b/apps/note/api/views.py @@ -179,19 +179,10 @@ class ConsumerViewSet(ReadOnlyProtectedModelViewSet): # We match first an alias if it is matched without normalization, # then if the normalized pattern matches a normalized alias. queryset = queryset.filter( - **{f'name{suffix}': alias_prefix + alias} - ).union( - queryset.filter( - Q(**{f'normalized_name{suffix}': alias_prefix + Alias.normalize(alias)}) - & ~Q(**{f'name{suffix}': alias_prefix + alias}) - ), - all=True).union( - queryset.filter( - Q(**{f'normalized_name{suffix}': alias_prefix + alias.lower()}) - & ~Q(**{f'normalized_name{suffix}': alias_prefix + Alias.normalize(alias)}) - & ~Q(**{f'name{suffix}': alias_prefix + alias}) - ), - all=True) + Q(**{f'name{suffix}': alias_prefix + alias}) + | Q(**{f'normalized_name{suffix}': alias_prefix + Alias.normalize(alias)}) + | Q(**{f'normalized_name{suffix}': alias_prefix + alias.lower()}) + ) queryset = queryset if settings.DATABASES[queryset.db]["ENGINE"] == 'django.db.backends.postgresql' \ else queryset.order_by("name") diff --git a/apps/note/forms.py b/apps/note/forms.py index 209b49d9..92e17569 100644 --- a/apps/note/forms.py +++ b/apps/note/forms.py @@ -1,13 +1,15 @@ # Copyright (C) 2018-2024 by BDE ENS Paris-Saclay # SPDX-License-Identifier: GPL-3.0-or-later + from datetime import datetime +from bootstrap_datepicker_plus.widgets import DateTimePickerInput from django import forms from django.contrib.contenttypes.models import ContentType from django.forms import CheckboxSelectMultiple from django.utils.timezone import make_aware from django.utils.translation import gettext_lazy as _ -from note_kfet.inputs import Autocomplete, AmountInput, DateTimePickerInput +from note_kfet.inputs import Autocomplete, AmountInput from .models import TransactionTemplate, NoteClub, Alias diff --git a/apps/note/migrations/0002_create_special_notes.py b/apps/note/migrations/0002_create_special_notes.py index 12fa8583..07935d54 100644 --- a/apps/note/migrations/0002_create_special_notes.py +++ b/apps/note/migrations/0002_create_special_notes.py @@ -18,6 +18,7 @@ def create_special_notes(apps, schema_editor): class Migration(migrations.Migration): dependencies = [ ('note', '0001_initial'), + ('logs', '0001_initial'), ] operations = [ diff --git a/apps/note/migrations/0007_alter_note_polymorphic_ctype_and_more.py b/apps/note/migrations/0007_alter_note_polymorphic_ctype_and_more.py new file mode 100644 index 00000000..171263a2 --- /dev/null +++ b/apps/note/migrations/0007_alter_note_polymorphic_ctype_and_more.py @@ -0,0 +1,25 @@ +# Generated by Django 5.0.7 on 2024-07-11 09:24 + +import django.db.models.deletion +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('contenttypes', '0002_remove_content_type_name'), + ('note', '0006_trust'), + ] + + operations = [ + migrations.AlterField( + model_name='note', + name='polymorphic_ctype', + field=models.ForeignKey(editable=False, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='polymorphic_%(app_label)s.%(class)s_set+', to='contenttypes.contenttype'), + ), + migrations.AlterField( + model_name='transaction', + name='polymorphic_ctype', + field=models.ForeignKey(editable=False, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='polymorphic_%(app_label)s.%(class)s_set+', to='contenttypes.contenttype'), + ), + ] diff --git a/apps/note/templates/note/amount_input.html b/apps/note/templates/note/amount_input.html index d4873115..0f18adb7 100644 --- a/apps/note/templates/note/amount_input.html +++ b/apps/note/templates/note/amount_input.html @@ -9,7 +9,7 @@ SPDX-License-Identifier: GPL-3.0-or-later name="{{ widget.name }}" {# Other attributes are loaded #} {% for name, value in widget.attrs.items %} - {% ifnotequal value False %}{{ name }}{% ifnotequal value True %}="{{ value|stringformat:'s' }}"{% endifnotequal %}{% endifnotequal %} + {% if value != False %}{{ name }}{% if value != True %}="{{ value|stringformat:'s' }}"{% endif %}{% endif %} {% endfor %}>
diff --git a/apps/treasury/migrations/0009_alter_sogecredit_transactions.py b/apps/treasury/migrations/0009_alter_sogecredit_transactions.py new file mode 100644 index 00000000..fca19514 --- /dev/null +++ b/apps/treasury/migrations/0009_alter_sogecredit_transactions.py @@ -0,0 +1,19 @@ +# Generated by Django 5.0.7 on 2024-07-11 09:24 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('note', '0007_alter_note_polymorphic_ctype_and_more'), + ('treasury', '0008_auto_20240322_0045'), + ] + + operations = [ + migrations.AlterField( + model_name='sogecredit', + name='transactions', + field=models.ManyToManyField(blank=True, related_name='+', to='note.membershiptransaction', verbose_name='membership transactions'), + ), + ] diff --git a/apps/wei/forms/registration.py b/apps/wei/forms/registration.py index 808d7eda..53f27a66 100644 --- a/apps/wei/forms/registration.py +++ b/apps/wei/forms/registration.py @@ -1,13 +1,14 @@ # Copyright (C) 2018-2024 by BDE ENS Paris-Saclay # SPDX-License-Identifier: GPL-3.0-or-later +from bootstrap_datepicker_plus.widgets import DatePickerInput from django import forms from django.contrib.auth.models import User from django.db.models import Q from django.forms import CheckboxSelectMultiple from django.utils.translation import gettext_lazy as _ from note.models import NoteSpecial, NoteUser -from note_kfet.inputs import AmountInput, DatePickerInput, Autocomplete, ColorWidget +from note_kfet.inputs import AmountInput, Autocomplete, ColorWidget from ..models import WEIClub, WEIRegistration, Bus, BusTeam, WEIMembership, WEIRole diff --git a/apps/wei/tests/test_wei_registration.py b/apps/wei/tests/test_wei_registration.py index 74fdcf0b..bb57df8d 100644 --- a/apps/wei/tests/test_wei_registration.py +++ b/apps/wei/tests/test_wei_registration.py @@ -439,7 +439,7 @@ class TestWEIRegistration(TestCase): emergency_contact_phone='+33123456789', )) self.assertEqual(response.status_code, 200) - self.assertTrue("This user can't be in her/his first year since he/she has already participated to a WEI." + self.assertTrue("This user can't be in her/his first year since he/she has already participated to a WEI." in str(response.context["form"].errors)) # Check that if the WEI is started, we can't register anyone @@ -635,7 +635,7 @@ class TestWEIRegistration(TestCase): )) self.assertEqual(response.status_code, 200) self.assertFalse(response.context["form"].is_valid()) - self.assertTrue("This team doesn't belong to the given bus." in str(response.context["form"].errors)) + self.assertTrue("This team doesn't belong to the given bus." in str(response.context["form"].errors)) response = self.client.post(reverse("wei:validate_registration", kwargs=dict(pk=self.registration.pk)), dict( roles=[WEIRole.objects.get(name="GC WEI").id], diff --git a/note_kfet/admin.py b/note_kfet/admin.py index 0900c3b0..1d4b493d 100644 --- a/note_kfet/admin.py +++ b/note_kfet/admin.py @@ -25,19 +25,13 @@ admin_site.register(Site, SiteAdmin) # Add external apps model if "oauth2_provider" in settings.INSTALLED_APPS: - from oauth2_provider.admin import Application, ApplicationAdmin, Grant, \ - GrantAdmin, AccessToken, AccessTokenAdmin, RefreshToken, RefreshTokenAdmin + from oauth2_provider.admin import ApplicationAdmin, GrantAdmin, AccessTokenAdmin, RefreshTokenAdmin + from oauth2_provider.models import Application, Grant, AccessToken, RefreshToken admin_site.register(Application, ApplicationAdmin) admin_site.register(Grant, GrantAdmin) admin_site.register(AccessToken, AccessTokenAdmin) admin_site.register(RefreshToken, RefreshTokenAdmin) -if "django_htcpcp_tea" in settings.INSTALLED_APPS: - from django_htcpcp_tea.admin import * - from django_htcpcp_tea.models import * - admin_site.register(Pot, PotAdmin) - admin_site.register(TeaType, TeaTypeAdmin) - admin_site.register(Addition, AdditionAdmin) if "mailer" in settings.INSTALLED_APPS: from mailer.admin import * @@ -50,9 +44,3 @@ if "rest_framework" in settings.INSTALLED_APPS: from rest_framework.authtoken.admin import * from rest_framework.authtoken.models import * admin_site.register(Token, TokenAdmin) - -if "cas_server" in settings.INSTALLED_APPS: - from cas_server.admin import * - from cas_server.models import * - admin_site.register(ServicePattern, ServicePatternAdmin) - admin_site.register(FederatedIendityProvider, FederatedIendityProviderAdmin) diff --git a/note_kfet/settings/base.py b/note_kfet/settings/base.py index 74fed818..9a27fc46 100644 --- a/note_kfet/settings/base.py +++ b/note_kfet/settings/base.py @@ -41,7 +41,7 @@ INSTALLED_APPS = [ 'bootstrap_datepicker_plus', 'colorfield', 'crispy_forms', - 'django_htcpcp_tea', + 'crispy_bootstrap4', 'django_tables2', 'mailer', 'phonenumber_field', @@ -90,7 +90,6 @@ MIDDLEWARE = [ 'django.middleware.clickjacking.XFrameOptionsMiddleware', 'django.middleware.locale.LocaleMiddleware', 'django.contrib.sites.middleware.CurrentSiteMiddleware', - 'django_htcpcp_tea.middleware.HTCPCPTeaMiddleware', 'note_kfet.middlewares.SessionMiddleware', 'note_kfet.middlewares.LoginByIPMiddleware', 'note_kfet.middlewares.TurbolinksMiddleware', @@ -295,3 +294,6 @@ PHONENUMBER_DEFAULT_REGION = 'FR' # We add custom information to CAS, in order to give a normalized name to other services CAS_AUTH_CLASS = 'member.auth.CustomAuthUser' + +# Default field for primary key +DEFAULT_AUTO_FIELD = "django.db.models.AutoField" diff --git a/note_kfet/templates/autocomplete_model.html b/note_kfet/templates/autocomplete_model.html index fa24213f..05fc4957 100644 --- a/note_kfet/templates/autocomplete_model.html +++ b/note_kfet/templates/autocomplete_model.html @@ -8,7 +8,7 @@ SPDX-License-Identifier: GPL-3.0-or-later {% if widget.value != None and widget.value != "" %}value="{{ widget.value }}"{% endif %} name="{{ widget.name }}_name" autocomplete="off" {% for name, value in widget.attrs.items %} - {% ifnotequal value False %}{{ name }}{% ifnotequal value True %}="{{ value|stringformat:'s' }}"{% endifnotequal %}{% endifnotequal %} + {% if value != False %}{{ name }}{% if value != True %}="{{ value|stringformat:'s' }}"{% endif %}{% endif %} {% endfor %} aria-describedby="{{widget.attrs.id}}_tooltip"> {% if widget.resetable %} diff --git a/note_kfet/templates/base.html b/note_kfet/templates/base.html index 63d0ddfe..5723c3bc 100644 --- a/note_kfet/templates/base.html +++ b/note_kfet/templates/base.html @@ -126,9 +126,12 @@ SPDX-License-Identifier: GPL-3.0-or-later {% trans "My account" %} - +
+ {% csrf_token %} + +
{% else %} diff --git a/note_kfet/urls.py b/note_kfet/urls.py index d222c239..72f5dafb 100644 --- a/note_kfet/urls.py +++ b/note_kfet/urls.py @@ -30,9 +30,6 @@ urlpatterns = [ path('accounts/', include('django.contrib.auth.urls')), path('api/', include('api.urls')), path('permission/', include('permission.urls')), - - # Make coffee - path('coffee/', include('django_htcpcp_tea.urls')), ] # During development, serve static and media files @@ -46,11 +43,6 @@ if "oauth2_provider" in settings.INSTALLED_APPS: path('o/', include('oauth2_provider.urls', namespace='oauth2_provider')) ) -if "cas_server" in settings.INSTALLED_APPS: - urlpatterns.append( - path('cas/', include('cas_server.urls', namespace='cas_server')) - ) - if "debug_toolbar" in settings.INSTALLED_APPS: import debug_toolbar urlpatterns = [ diff --git a/requirements.txt b/requirements.txt index f4ece220..eb881811 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,19 +1,17 @@ -beautifulsoup4~=4.7.1 -Django~=2.2.15 -django-bootstrap-datepicker-plus~=3.0.5 -django-cas-server~=1.2.0 -django-colorfield~=0.3.2 -django-crispy-forms~=1.7.2 -django-extensions>=2.1.4 -django-filter~=2.1 -django-htcpcp-tea~=0.3.1 -django-mailer~=2.0.1 -django-oauth-toolkit~=1.3.3 -django-phonenumber-field~=5.0.0 -django-polymorphic>=2.0.3,<3.0.0 -djangorestframework>=3.9.0,<3.13.0 -django-rest-polymorphic~=0.1.9 -django-tables2~=2.3.1 -python-memcached~=1.59 -phonenumbers~=8.9.10 +beautifulsoup4~=4.12.3 +crispy-bootstrap4~=2024.1 +Django~=5.0.7 +django-bootstrap-datepicker-plus~=5.0.5 +django-colorfield~=0.11.0 +django-crispy-forms~=2.2 +django-extensions~=3.2.3 +django-filter~=24.2 +django-mailer~=2.3.2 +django-oauth-toolkit~=2.4.0 +django-phonenumber-field~=8.0.0 +django-polymorphic~=3.1.0 +django-rest-polymorphic~=0.1.10 +django-tables2~=2.7.0 +djangorestframework~=3.15.2 +phonenumbers~=8.13.40 Pillow>=5.4.1 diff --git a/tox.ini b/tox.ini index ad3c6798..16ae7d94 100644 --- a/tox.ini +++ b/tox.ini @@ -1,13 +1,10 @@ [tox] envlist = - # Debian Buster Python - py37-django22 - # Ubuntu 20.04 Python - py38-django22 + py310-django50 # Debian Bullseye Python - py39-django22 + py311-django50 linters skipsdist = True