diff --git a/.gitignore b/.gitignore index 67898914..ea48820c 100644 --- a/.gitignore +++ b/.gitignore @@ -105,4 +105,5 @@ ve/ # miscellaneous .idea/* +/static/ media/* diff --git a/blitz_api/admin.py b/blitz_api/admin.py index 79c6b58c..781d61d3 100644 --- a/blitz_api/admin.py +++ b/blitz_api/admin.py @@ -4,7 +4,7 @@ from django.contrib.auth.admin import UserAdmin from django.contrib.auth.forms import UserChangeForm, UserCreationForm from django.contrib.auth.models import AbstractUser, Permission -from django.utils.translation import ugettext_lazy as _ +from django.utils.translation import gettext_lazy as _ from import_export.admin import ExportActionModelAdmin from modeltranslation.admin import TranslationAdmin from simple_history.admin import SimpleHistoryAdmin diff --git a/blitz_api/authentication.py b/blitz_api/authentication.py index e4c79e52..c81e95c7 100644 --- a/blitz_api/authentication.py +++ b/blitz_api/authentication.py @@ -2,7 +2,7 @@ from rest_framework.authentication import TokenAuthentication from django.utils import timezone -from django.utils.translation import ugettext_lazy as _ +from django.utils.translation import gettext_lazy as _ from django.conf import settings from .models import TemporaryToken diff --git a/blitz_api/models.py b/blitz_api/models.py index 2038fee5..16904da9 100644 --- a/blitz_api/models.py +++ b/blitz_api/models.py @@ -10,7 +10,7 @@ from django.db.models import Sum from django.utils import timezone from django.contrib.auth.models import AbstractUser -from django.utils.translation import ugettext_lazy as _ +from django.utils.translation import gettext_lazy as _ from dateutil.relativedelta import relativedelta from jsonfield import JSONField diff --git a/blitz_api/serializers.py b/blitz_api/serializers.py index 4a017602..6bb00281 100644 --- a/blitz_api/serializers.py +++ b/blitz_api/serializers.py @@ -7,7 +7,7 @@ from rest_framework.authtoken.serializers import AuthTokenSerializer from django.contrib.auth import (get_user_model, password_validation, authenticate, ) -from django.utils.translation import ugettext_lazy as _ +from django.utils.translation import gettext_lazy as _ from django.conf import settings from django.core.exceptions import ValidationError diff --git a/blitz_api/services.py b/blitz_api/services.py index 61c7aca4..d0610ded 100644 --- a/blitz_api/services.py +++ b/blitz_api/services.py @@ -8,7 +8,7 @@ from django.conf import settings from django.core.mail import EmailMessage from django.http import HttpResponse -from django.utils.translation import ugettext_lazy as _ +from django.utils.translation import gettext_lazy as _ from django.template.loader import render_to_string from rest_framework.pagination import PageNumberPagination diff --git a/blitz_api/settings.py b/blitz_api/settings.py index a2cce32a..1a5bfe93 100644 --- a/blitz_api/settings.py +++ b/blitz_api/settings.py @@ -18,7 +18,7 @@ import sys from decouple import config, Csv -from django.utils.translation import ugettext_lazy as _ +from django.utils.translation import gettext_lazy as _ from dj_database_url import parse as db_url IS_GAE_ENV = config('GAE_INSTANCE', False) @@ -152,7 +152,7 @@ DATABASES = { 'default': { - 'ENGINE': 'django.db.backends.postgresql_psycopg2', + 'ENGINE': 'django.db.backends.postgresql', 'HOST': config('DB_HOST', default="postgres"), 'USER': config('DB_USER', default='my_db_user'), 'PASSWORD': config('DB_PASSWORD', default='my_db_password'), @@ -510,7 +510,7 @@ CELERY_RESULT_BACKEND = 'django-db' CELERY_RESULT_BACKEND_DB = ''.join( [ - 'postgresql+psycopg2://', + 'postgresql://', config("DB_USER", default='myprojectuser'), ":", config("DB_PASSWORD", default='password'), diff --git a/blitz_api/tests/tests_view_Users.py b/blitz_api/tests/tests_view_Users.py index cdc8a6f3..5175b499 100644 --- a/blitz_api/tests/tests_view_Users.py +++ b/blitz_api/tests/tests_view_Users.py @@ -851,3 +851,72 @@ def test_credit_ticket_negative_int(self): response.status_code, status.HTTP_400_BAD_REQUEST, ) + + def test_member_filter(self): + """ + Ensure we can list members while filtering + """ + now = timezone.now() + str_now = now.strftime("%Y-%m-%d") + self.user.delete() + self.client.force_authenticate(user=self.admin) + + new_membership = Membership.objects.create( + name="new_1", + available=True, + price=50, + duration=timedelta(days=365), + ) + + new_membership_2 = Membership.objects.create( + name="new_2", + available=True, + price=50, + duration=timedelta(days=365), + ) + + inactive_user = UserFactory() + inactive_user.is_active = False + inactive_user.save() + + active_user = UserFactory() + active_user.is_active = True + active_user.save() + + membership_ended_user = UserFactory() + membership_ended_user.is_active = True + membership_ended_user.membership = new_membership + membership_ended_user.membership_end = now - relativedelta(days=1) + membership_ended_user.save() + + membership_1_user = UserFactory() + membership_1_user.is_active = True + membership_1_user.membership = new_membership + membership_1_user.membership_end = now + relativedelta(days=1) + membership_1_user.save() + + membership_2_user = UserFactory() + membership_2_user.is_active = True + membership_2_user.membership = new_membership_2 + membership_2_user.membership_end = now + relativedelta(days=1) + membership_2_user.save() + + inactive_filter = f'?is_active=false' + active_filter = f'?is_active=true' + active_member = f'?is_active=true&membership_end_after={str_now}' + active_target_member = (f'?is_active=true' + f'&membership_end_after={str_now}' + f'&membership={new_membership.id}') + + response = self.client.get(reverse('user-list') + inactive_filter) + self.assertEqual(json.loads(response.content)['count'], 1) + + response = self.client.get(reverse('user-list') + active_filter) + # 5 including admin + self.assertEqual(json.loads(response.content)['count'], 5) + + response = self.client.get(reverse('user-list') + active_member) + self.assertEqual(json.loads(response.content)['count'], 2) + + response = self.client.get(reverse('user-list') + active_target_member) + self.assertEqual(json.loads(response.content)['count'], 1) diff --git a/blitz_api/views.py b/blitz_api/views.py index d194948e..8c8d14b6 100644 --- a/blitz_api/views.py +++ b/blitz_api/views.py @@ -5,8 +5,13 @@ from django.utils import timezone from django.http import Http404 from django.core.exceptions import ValidationError -from django.utils.translation import ugettext_lazy as _ - +from django.utils.translation import gettext_lazy as _ +from django_filters import ( + FilterSet, + DateFilter, + NumberFilter, + BooleanFilter, +) from rest_framework import status, viewsets, mixins, generics from rest_framework.decorators import action from rest_framework.parsers import MultiPartParser @@ -36,6 +41,28 @@ LOCAL_TIMEZONE = pytz.timezone(settings.TIME_ZONE) +class UserFilter(FilterSet): + membership_end_after = DateFilter( + field_name='membership_end', + lookup_expr='gte', + ) + university = NumberFilter( + field_name='university__id', + lookup_expr='exact', + ) + membership = NumberFilter( + field_name='membership__id', + lookup_expr='exact', + ) + is_active = BooleanFilter( + field_name='is_active' + ) + + class Meta: + model = User + fields = '__all__' + + class UserViewSet(ExportMixin, viewsets.ModelViewSet): """ retrieve: @@ -54,26 +81,7 @@ class UserViewSet(ExportMixin, viewsets.ModelViewSet): Sets the user inactive. """ queryset = User.objects.all() - filterset_fields = { - 'email', - 'phone', - 'other_phone', - 'academic_field', - 'university', - 'academic_level', - 'membership', - 'last_login', - 'first_name', - 'last_name', - 'is_active', - 'date_joined', - 'birthdate', - 'gender', - 'membership_end', - 'tickets', - 'groups', - 'user_permissions', - } + filterset_class = UserFilter search_fields = ('first_name', 'last_name', 'email') ordering = ('email',) @@ -646,7 +654,7 @@ class MailChimpView(generics.CreateAPIView): class MagicLinkViewSet(viewsets.ModelViewSet): serializer_class = serializers.MagicLinkSerializer queryset = MagicLink.objects.all() - filter_fields = ('type',) + filterset_fields = ('type',) permission_classes = [] def get_permissions(self): diff --git a/ckeditor_api/models.py b/ckeditor_api/models.py index d68840cb..30584098 100644 --- a/ckeditor_api/models.py +++ b/ckeditor_api/models.py @@ -1,5 +1,5 @@ from django.db import models -from django.utils.translation import ugettext_lazy as _ +from django.utils.translation import gettext_lazy as _ class CKEditorPage(models.Model): diff --git a/cron_manager/admin.py b/cron_manager/admin.py index d081ca72..4e7aaa09 100644 --- a/cron_manager/admin.py +++ b/cron_manager/admin.py @@ -2,7 +2,7 @@ from django.contrib import admin from . import models -from django.utils.translation import ugettext_lazy as _ +from django.utils.translation import gettext_lazy as _ from django_admin_inline_paginator.admin import TabularInlinePaginated diff --git a/cron_manager/models.py b/cron_manager/models.py index 226dfe82..03043c8b 100644 --- a/cron_manager/models.py +++ b/cron_manager/models.py @@ -4,7 +4,7 @@ from django.db import models from django.utils import timezone -from django.utils.translation import ugettext_lazy as _ +from django.utils.translation import gettext_lazy as _ class Task(models.Model): diff --git a/log_management/models.py b/log_management/models.py index 2b636611..97acc10d 100644 --- a/log_management/models.py +++ b/log_management/models.py @@ -3,7 +3,7 @@ from django.conf import settings from django.db import models -from django.utils.translation import ugettext_lazy as _ +from django.utils.translation import gettext_lazy as _ class Log(models.Model): diff --git a/requirements-dev.txt b/requirements-dev.txt index de03873c..39a2af20 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -2,9 +2,4 @@ pycodestyle==2.8.0 coveralls==3.2.0 responses==0.15.0 awscli==1.21.7 -six==1.16.0 - -# Please consider moving this line to the requirements.txt as soon as it will be fixed -# Hotfix to avoid installation problem if installed at the same time as django -# https://github.com/shinneider/django-admin-inline-paginator/issues/12 -django-admin-inline-paginator==0.2.1 \ No newline at end of file +six==1.16.0 \ No newline at end of file diff --git a/requirements.txt b/requirements.txt index 4c446bb8..58d2d22d 100644 --- a/requirements.txt +++ b/requirements.txt @@ -2,24 +2,25 @@ mkdocs==1.2.3 mkdocs-material==7.3.6 -Django==3.2.8 -djangorestframework==3.12.4 -django-cors-headers==3.10.0 -django-filter==21.1 +Django==4.2.5 +djangorestframework==3.14.0 +django-cors-headers==3.11.0 +django-filter==23.4 coreapi==2.3.3 factory-boy==3.2.1 Pygments==2.10.0 Markdown==3.3.4 -django-anymail==8.4 -Pillow==8.4.0 +django-anymail==10.2 +Pillow==9.1.0 django-simple-history==3.0.0 python-decouple==3.5 -django-storages==1.12.2 +django-storages==1.14.2 dj_database_url==0.5.0 zappa==0.54.0 -psycopg2-binary==2.9.1 -django-safedelete==0.5.6 -django-request-logging==0.7.3 +psycopg-binary==3.1.12 +psycopg==3.1.12 +django-safedelete==1.3.3 +django-request-logging==0.7.5 django-modeltranslation==0.17.3 django-import-export==2.6.1 jsonfield==3.1.0 @@ -31,13 +32,14 @@ mailchimp3==3.0.14 babel==2.9.1 troposphere==3.1.0 -asgiref==3.4.1 +django-admin-inline-paginator==0.4.0 +asgiref==3.7.2 # Google cloud platform -google-cloud-storage==1.42.3 +google-cloud-storage==2.8.0 # Celery -celery[pytest]==5.1.2 -pytest==6.2.4 -django-celery-results==2.2.0 -django-celery-beat==2.2.1 +celery[pytest]==5.2.7 +pytest==7.2.2 +django-celery-results==2.5.1 +django-celery-beat==2.5.0 diff --git a/retirement/admin.py b/retirement/admin.py index 91f66e64..ea5d1acb 100644 --- a/retirement/admin.py +++ b/retirement/admin.py @@ -2,7 +2,7 @@ from django.contrib import admin from django.contrib.auth import get_user_model from django.http import HttpResponse -from django.utils.translation import ugettext_lazy as _ +from django.utils.translation import gettext_lazy as _ from import_export.admin import ExportActionModelAdmin from modeltranslation.admin import TranslationAdmin from safedelete.admin import ( diff --git a/retirement/fields.py b/retirement/fields.py index 5feb7fba..d966ff41 100644 --- a/retirement/fields.py +++ b/retirement/fields.py @@ -2,7 +2,7 @@ from rest_framework import serializers -from django.utils.translation import ugettext_lazy as _ +from django.utils.translation import gettext_lazy as _ class TimezoneField(serializers.CharField): diff --git a/retirement/migrations/0065_historicalreservation_deleted_by_cascade_and_more.py b/retirement/migrations/0065_historicalreservation_deleted_by_cascade_and_more.py new file mode 100644 index 00000000..28cf090f --- /dev/null +++ b/retirement/migrations/0065_historicalreservation_deleted_by_cascade_and_more.py @@ -0,0 +1,73 @@ +# Generated by Django 4.2.5 on 2023-11-28 18:03 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('retirement', '0064_retreatdate_tomatoes_assigned'), + ] + + operations = [ + migrations.AddField( + model_name='historicalreservation', + name='deleted_by_cascade', + field=models.BooleanField(default=False, editable=False), + ), + migrations.AddField( + model_name='historicalretreat', + name='deleted_by_cascade', + field=models.BooleanField(default=False, editable=False), + ), + migrations.AddField( + model_name='historicalretreatinvitation', + name='deleted_by_cascade', + field=models.BooleanField(default=False, editable=False), + ), + migrations.AddField( + model_name='reservation', + name='deleted_by_cascade', + field=models.BooleanField(default=False, editable=False), + ), + migrations.AddField( + model_name='retreat', + name='deleted_by_cascade', + field=models.BooleanField(default=False, editable=False), + ), + migrations.AddField( + model_name='retreatinvitation', + name='deleted_by_cascade', + field=models.BooleanField(default=False, editable=False), + ), + migrations.AlterField( + model_name='historicalreservation', + name='deleted', + field=models.DateTimeField(db_index=True, editable=False, null=True), + ), + migrations.AlterField( + model_name='historicalretreat', + name='deleted', + field=models.DateTimeField(db_index=True, editable=False, null=True), + ), + migrations.AlterField( + model_name='historicalretreatinvitation', + name='deleted', + field=models.DateTimeField(db_index=True, editable=False, null=True), + ), + migrations.AlterField( + model_name='reservation', + name='deleted', + field=models.DateTimeField(db_index=True, editable=False, null=True), + ), + migrations.AlterField( + model_name='retreat', + name='deleted', + field=models.DateTimeField(db_index=True, editable=False, null=True), + ), + migrations.AlterField( + model_name='retreatinvitation', + name='deleted', + field=models.DateTimeField(db_index=True, editable=False, null=True), + ), + ] diff --git a/retirement/models.py b/retirement/models.py index 21930d0a..4eaa8a13 100644 --- a/retirement/models.py +++ b/retirement/models.py @@ -20,7 +20,7 @@ from django.contrib.auth import get_user_model from django.db import models, transaction from django.utils.html import format_html -from django.utils.translation import ugettext_lazy as _ +from django.utils.translation import gettext_lazy as _ from safedelete.models import SafeDeleteModel from simple_history.models import HistoricalRecords diff --git a/retirement/serializers.py b/retirement/serializers.py index 9c552cf7..74550722 100644 --- a/retirement/serializers.py +++ b/retirement/serializers.py @@ -9,7 +9,7 @@ from django.db import transaction from django.template.loader import render_to_string from django.utils import timezone -from django.utils.translation import ugettext_lazy as _ +from django.utils.translation import gettext_lazy as _ from rest_framework import serializers from rest_framework.reverse import reverse from rest_framework.validators import UniqueValidator @@ -261,7 +261,7 @@ def to_representation(self, instance): class Meta: model = Retreat - exclude = ('deleted', 'users') + exclude = ('deleted', 'deleted_by_cascade', 'users') extra_kwargs = { 'details': { 'help_text': _("Description of the retreat.") @@ -935,7 +935,7 @@ def to_representation(self, instance): class Meta: model = Reservation - exclude = ('deleted', ) + exclude = ('deleted', 'deleted_by_cascade') extra_kwargs = { 'retreat': { 'help_text': _("Retreat represented by the picture."), diff --git a/retirement/tests/tests_viewset_RetreatUsageLog.py b/retirement/tests/tests_viewset_RetreatUsageLog.py index 8b050db0..3a625b8f 100644 --- a/retirement/tests/tests_viewset_RetreatUsageLog.py +++ b/retirement/tests/tests_viewset_RetreatUsageLog.py @@ -161,7 +161,7 @@ def test_create_retreat_usage_log_on_somebody_else_reservation(self): content = json.loads(response.content) - self.assertEquals( + self.assertEqual( content, { 'reservation': [ diff --git a/retirement/tests/tests_viewset_Wait_Queue_Place.py b/retirement/tests/tests_viewset_Wait_Queue_Place.py index 4e497d96..bd6e40c1 100644 --- a/retirement/tests/tests_viewset_Wait_Queue_Place.py +++ b/retirement/tests/tests_viewset_Wait_Queue_Place.py @@ -131,7 +131,7 @@ def check_user_has_reserved_place( ) def check_count_wait_queue_place(self, wait_queue_place, count): - self.assertEquals( + self.assertEqual( WaitQueuePlaceReserved.objects.filter( wait_queue_place=wait_queue_place, used=False, diff --git a/retirement/views.py b/retirement/views.py index 5c43da62..6c44f80e 100644 --- a/retirement/views.py +++ b/retirement/views.py @@ -19,7 +19,7 @@ from django.contrib.auth import get_user_model from django.db import transaction from django.utils import timezone -from django.utils.translation import ugettext_lazy as _ +from django.utils.translation import gettext_lazy as _ from rest_framework import ( mixins, @@ -169,7 +169,7 @@ class RetreatViewSet(ExportMixin, viewsets.ModelViewSet): 'display_start_time', ) - filter_class = RetreatFilter + filterset_class = RetreatFilter search_fields = ('name',) export_resource = RetreatResource() @@ -573,7 +573,7 @@ class ReservationViewSet(ExportMixin, viewsets.ModelViewSet): serializer_class = serializers.ReservationSerializer queryset = Reservation.objects.all() - filter_class = RetreatReservationFilter + filterset_class = RetreatReservationFilter ordering_fields = ( 'is_active', @@ -704,7 +704,7 @@ class RetreatInvitationViewSet(viewsets.ModelViewSet): serializer_class = serializers.RetreatInvitationSerializer queryset = RetreatInvitation.objects.all() permission_classes = (permissions.IsAdminOrReadOnly,) - filter_fields = '__all__' + filterset_fields = '__all__' class WaitQueuePlaceViewSet(viewsets.ModelViewSet): @@ -772,7 +772,7 @@ class RetreatDateViewSet(viewsets.ModelViewSet): serializer_class = RetreatDateSerializer queryset = RetreatDate.objects.all() permission_classes = [permissions.IsAdminOrReadOnly] - filter_fields = '__all__' + filterset_fields = '__all__' def update(self, request, *args, **kwargs): retreat_date: RetreatDate = self.get_object() @@ -835,7 +835,7 @@ class RetreatTypeViewSet(viewsets.ModelViewSet): serializer_class = RetreatTypeSerializer queryset = RetreatType.objects.all() permission_classes = [permissions.IsAdminOrReadOnly] - filter_fields = [ + filterset_fields = [ 'is_virtual', 'is_visible', ] @@ -856,11 +856,11 @@ class AutomaticEmailViewSet(viewsets.ModelViewSet): serializer_class = AutomaticEmailSerializer queryset = AutomaticEmail.objects.all() permission_classes = [permissions.IsAdminOrReadOnly] - filter_fields = '__all__' + filterset_fields = '__all__' class RetreatUsageLogViewSet(viewsets.ModelViewSet): serializer_class = RetreatUsageLogSerializer queryset = RetreatUsageLog.objects.all() permission_classes = [IsAuthenticated] - filter_fields = '__all__' + filterset_fields = '__all__' diff --git a/store/admin.py b/store/admin.py index 2fc55557..5a695fb7 100644 --- a/store/admin.py +++ b/store/admin.py @@ -1,6 +1,6 @@ from admin_auto_filters.filters import AutocompleteFilter from django.contrib import admin -from django.utils.translation import ugettext_lazy as _ +from django.utils.translation import gettext_lazy as _ from import_export.admin import ExportActionModelAdmin from modeltranslation.admin import TranslationAdmin from safedelete.admin import SafeDeleteAdmin, highlight_deleted diff --git a/store/migrations/0049_coupon_deleted_by_cascade_and_more.py b/store/migrations/0049_coupon_deleted_by_cascade_and_more.py new file mode 100644 index 00000000..cbfcde70 --- /dev/null +++ b/store/migrations/0049_coupon_deleted_by_cascade_and_more.py @@ -0,0 +1,145 @@ +# Generated by Django 4.2.5 on 2023-11-28 18:03 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('retirement', '0065_historicalreservation_deleted_by_cascade_and_more'), + ('workplace', '0028_historicalperiod_deleted_by_cascade_and_more'), + ('store', '0048_autopopulate_orderline_total_cost'), + ] + + operations = [ + migrations.AddField( + model_name='coupon', + name='deleted_by_cascade', + field=models.BooleanField(default=False, editable=False), + ), + migrations.AddField( + model_name='couponuser', + name='deleted_by_cascade', + field=models.BooleanField(default=False, editable=False), + ), + migrations.AddField( + model_name='historicalcoupon', + name='deleted_by_cascade', + field=models.BooleanField(default=False, editable=False), + ), + migrations.AddField( + model_name='historicalcouponuser', + name='deleted_by_cascade', + field=models.BooleanField(default=False, editable=False), + ), + migrations.AddField( + model_name='historicalmembershipcoupon', + name='deleted_by_cascade', + field=models.BooleanField(default=False, editable=False), + ), + migrations.AddField( + model_name='historicalrefund', + name='deleted_by_cascade', + field=models.BooleanField(default=False, editable=False), + ), + migrations.AddField( + model_name='membershipcoupon', + name='deleted_by_cascade', + field=models.BooleanField(default=False, editable=False), + ), + migrations.AddField( + model_name='refund', + name='deleted_by_cascade', + field=models.BooleanField(default=False, editable=False), + ), + migrations.AlterField( + model_name='coupon', + name='applicable_memberships', + field=models.ManyToManyField(blank=True, related_name='applicable_%(class)ss', to='store.membership', verbose_name='Applicable memberships'), + ), + migrations.AlterField( + model_name='coupon', + name='applicable_packages', + field=models.ManyToManyField(blank=True, related_name='applicable_%(class)ss', to='store.package', verbose_name='Applicable packages'), + ), + migrations.AlterField( + model_name='coupon', + name='applicable_retreat_types', + field=models.ManyToManyField(blank=True, related_name='applicable_%(class)ss', to='retirement.retreattype', verbose_name='Applicable retreat types'), + ), + migrations.AlterField( + model_name='coupon', + name='applicable_retreats', + field=models.ManyToManyField(blank=True, related_name='applicable_%(class)ss', to='retirement.retreat', verbose_name='Applicable retreats'), + ), + migrations.AlterField( + model_name='coupon', + name='applicable_timeslots', + field=models.ManyToManyField(blank=True, related_name='applicable_%(class)ss', to='workplace.timeslot', verbose_name='Applicable timeslots'), + ), + migrations.AlterField( + model_name='coupon', + name='deleted', + field=models.DateTimeField(db_index=True, editable=False, null=True), + ), + migrations.AlterField( + model_name='couponuser', + name='deleted', + field=models.DateTimeField(db_index=True, editable=False, null=True), + ), + migrations.AlterField( + model_name='historicalcoupon', + name='deleted', + field=models.DateTimeField(db_index=True, editable=False, null=True), + ), + migrations.AlterField( + model_name='historicalcouponuser', + name='deleted', + field=models.DateTimeField(db_index=True, editable=False, null=True), + ), + migrations.AlterField( + model_name='historicalmembershipcoupon', + name='deleted', + field=models.DateTimeField(db_index=True, editable=False, null=True), + ), + migrations.AlterField( + model_name='historicalrefund', + name='deleted', + field=models.DateTimeField(db_index=True, editable=False, null=True), + ), + migrations.AlterField( + model_name='membershipcoupon', + name='applicable_memberships', + field=models.ManyToManyField(blank=True, related_name='applicable_%(class)ss', to='store.membership', verbose_name='Applicable memberships'), + ), + migrations.AlterField( + model_name='membershipcoupon', + name='applicable_packages', + field=models.ManyToManyField(blank=True, related_name='applicable_%(class)ss', to='store.package', verbose_name='Applicable packages'), + ), + migrations.AlterField( + model_name='membershipcoupon', + name='applicable_retreat_types', + field=models.ManyToManyField(blank=True, related_name='applicable_%(class)ss', to='retirement.retreattype', verbose_name='Applicable retreat types'), + ), + migrations.AlterField( + model_name='membershipcoupon', + name='applicable_retreats', + field=models.ManyToManyField(blank=True, related_name='applicable_%(class)ss', to='retirement.retreat', verbose_name='Applicable retreats'), + ), + migrations.AlterField( + model_name='membershipcoupon', + name='applicable_timeslots', + field=models.ManyToManyField(blank=True, related_name='applicable_%(class)ss', to='workplace.timeslot', verbose_name='Applicable timeslots'), + ), + migrations.AlterField( + model_name='membershipcoupon', + name='deleted', + field=models.DateTimeField(db_index=True, editable=False, null=True), + ), + migrations.AlterField( + model_name='refund', + name='deleted', + field=models.DateTimeField(db_index=True, editable=False, null=True), + ), + ] diff --git a/store/models.py b/store/models.py index 058061f7..c380ad48 100644 --- a/store/models.py +++ b/store/models.py @@ -10,7 +10,7 @@ from django.db import models from django.db.models import Sum -from django.utils.translation import ugettext_lazy as _ +from django.utils.translation import gettext_lazy as _ from django.conf import settings from django.contrib.auth import get_user_model from django.contrib.contenttypes.fields import ( diff --git a/store/serializers.py b/store/serializers.py index 959107da..d5b607c6 100644 --- a/store/serializers.py +++ b/store/serializers.py @@ -17,7 +17,7 @@ from django.apps import apps from django.utils import timezone -from django.utils.translation import ugettext_lazy as _ +from django.utils.translation import gettext_lazy as _ from django.contrib.auth import get_user_model from django.contrib.contenttypes.models import ContentType from django.db import transaction, models @@ -1255,7 +1255,7 @@ def to_representation(self, instance): class Meta: model = Coupon - exclude = ('deleted',) + exclude = ('deleted', 'deleted_by_cascade') extra_kwargs = { 'applicable_retreats': { 'required': False, @@ -1282,7 +1282,7 @@ class CouponUserSerializer(serializers.HyperlinkedModelSerializer): class Meta: model = CouponUser - exclude = ('deleted',) + exclude = ('deleted', 'deleted_by_cascade') class RefundSerializer(serializers.HyperlinkedModelSerializer): @@ -1290,4 +1290,4 @@ class RefundSerializer(serializers.HyperlinkedModelSerializer): class Meta: model = Refund - exclude = ('deleted',) + exclude = ('deleted', 'deleted_by_cascade') diff --git a/store/services.py b/store/services.py index 291c9906..3404dc6d 100644 --- a/store/services.py +++ b/store/services.py @@ -9,7 +9,7 @@ from django.db.models import Q from django.template.loader import render_to_string from django.utils import timezone -from django.utils.translation import ugettext_lazy as _ +from django.utils.translation import gettext_lazy as _ from log_management.models import Log, EmailLog from .exceptions import PaymentAPIError diff --git a/store/views.py b/store/views.py index ab5d540c..11dc7d98 100644 --- a/store/views.py +++ b/store/views.py @@ -7,7 +7,7 @@ from django.db import transaction from django.http import Http404, HttpResponse, HttpRequest from django.utils import timezone -from django.utils.translation import ugettext_lazy as _ +from django.utils.translation import gettext_lazy as _ from rest_framework import viewsets, status, mixins, exceptions from rest_framework import serializers as drf_serializers @@ -50,7 +50,7 @@ class BaseProductViewSet(ExportMixin, viewsets.ModelViewSet): serializer_class = serializers.BaseProductManagerSerializer queryset = BaseProduct.objects.all() permission_classes = (permissions.IsAdminOrReadOnly,) - filter_fields = { + filterset_fields = { 'available': ['exact'], 'name': ['exact'], 'price': ['exact', 'gte', 'lte'], @@ -90,7 +90,7 @@ class MembershipViewSet(ExportMixin, viewsets.ModelViewSet): serializer_class = serializers.MembershipSerializer queryset = Membership.objects.all() permission_classes = (permissions.IsAdminOrReadOnly,) - filter_fields = { + filterset_fields = { 'duration': ['exact', 'gte', 'lte'], 'academic_levels': ['exact', 'isnull'], 'details': ['exact'], @@ -136,7 +136,7 @@ class PackageViewSet(ExportMixin, viewsets.ModelViewSet): serializer_class = serializers.PackageSerializer queryset = Package.objects.all() permission_classes = (permissions.IsAdminOrReadOnly,) - filter_fields = { + filterset_fields = { 'reservations': ['exact', 'gte', 'lte'], 'exclusive_memberships': ['exact', 'isnull'], 'details': ['exact'], @@ -183,7 +183,7 @@ class OptionProductViewSet(ExportMixin, viewsets.ModelViewSet): queryset = OptionProduct.objects.all() permission_classes = (permissions.IsAdminOrReadOnly,) search_fields = ('name',) - filter_fields = { + filterset_fields = { 'available': ['exact'], } @@ -220,7 +220,7 @@ class PaymentProfileViewSet( serializer_class = serializers.PaymentProfileSerializer queryset = PaymentProfile.objects.all() permission_classes = (IsAuthenticated,) - filter_fields = '__all__' + filterset_fields = '__all__' def cards(self, request, *args, **kwargs): """ @@ -373,7 +373,7 @@ class OrderLineViewSet(ExportMixin, ChartJSMixin, viewsets.ModelViewSet): serializer_class = serializers.OrderLineSerializer queryset = OrderLine.objects.all() permission_classes = (IsAuthenticated,) - filter_fields = { + filterset_fields = { 'order__transaction_date': ['gte', 'lte'] } @@ -442,7 +442,7 @@ class CustomPaymentViewSet(ExportMixin, viewsets.ModelViewSet): serializer_class = serializers.CustomPaymentSerializer queryset = CustomPayment.objects.all() permission_classes = (IsAuthenticated, permissions.IsAdminOrReadOnly) - filter_fields = '__all__' + filterset_fields = '__all__' export_resource = CustomPaymentResource() @@ -473,7 +473,7 @@ class CouponViewSet(ExportMixin, viewsets.ModelViewSet): serializer_class = serializers.CouponSerializer queryset = Coupon.objects.all() permission_classes = (IsAuthenticated, permissions.IsAdminOrReadOnly) - filter_fields = { + filterset_fields = { 'start_time': ['exact', 'gte', 'lte'], 'end_time': ['exact', 'gte', 'lte'], 'code': ['exact'], @@ -558,7 +558,7 @@ class CouponUserViewSet(ExportMixin, viewsets.ModelViewSet): serializer_class = serializers.CouponUserSerializer queryset = CouponUser.objects.all() permission_classes = (IsAuthenticated, IsAdminUser) - filter_fields = '__all__' + filterset_fields = '__all__' export_resource = CouponUserResource() @@ -585,7 +585,7 @@ class RefundViewSet(ExportMixin, viewsets.GenericViewSet, serializer_class = serializers.RefundSerializer queryset = Refund.objects.all() permission_classes = (permissions.IsAdminOrReadOnly, IsAuthenticated) - filter_fields = '__all__' + filterset_fields = '__all__' export_resource = RefundResource() diff --git a/tomato/models.py b/tomato/models.py index 083ab7a9..4be15b64 100644 --- a/tomato/models.py +++ b/tomato/models.py @@ -1,7 +1,7 @@ from django.utils import timezone from django.conf import settings from django.db import models -from django.utils.translation import ugettext_lazy as _ +from django.utils.translation import gettext_lazy as _ from django.contrib.contenttypes.models import ContentType from django.contrib.contenttypes.fields import GenericForeignKey diff --git a/tomato/serializers.py b/tomato/serializers.py index 33ac8963..57dfec0e 100644 --- a/tomato/serializers.py +++ b/tomato/serializers.py @@ -3,7 +3,7 @@ from django.utils import timezone from django.contrib.auth import get_user_model -from django.utils.translation import ugettext_lazy as _ +from django.utils.translation import gettext_lazy as _ from rest_framework import serializers from tomato.models import ( diff --git a/tomato/views.py b/tomato/views.py index cdf7b7d0..82221d50 100644 --- a/tomato/views.py +++ b/tomato/views.py @@ -8,7 +8,7 @@ Report, Tomato, ) from django.db.models.functions import TruncMonth, TruncDay -from django.utils.translation import ugettext_lazy as _ +from django.utils.translation import gettext_lazy as _ from django.utils import timezone from rest_framework.response import Response from rest_framework import ( @@ -236,7 +236,7 @@ def get_permissions(self): class TomatoViewSet(viewsets.ModelViewSet): serializer_class = TomatoSerializer queryset = Tomato.objects.all() - filter_fields = { + filterset_fields = { 'user': ['exact'], 'source': ['exact'], 'acquisition_date': ['gte', 'lte'] diff --git a/wait_for_postgres.py b/wait_for_postgres.py index d105ce0f..81a9ffee 100644 --- a/wait_for_postgres.py +++ b/wait_for_postgres.py @@ -1,7 +1,7 @@ import os import logging from time import time, sleep -import psycopg2 +import psycopg check_timeout = os.getenv("POSTGRES_CHECK_TIMEOUT", 30) check_interval = os.getenv("POSTGRES_CHECK_INTERVAL", 1) interval_unit = "second" if check_interval == 1 else "seconds" @@ -21,11 +21,11 @@ def pg_isready(host, user, password, dbname): while time() - start_time < check_timeout: try: - conn = psycopg2.connect(**vars()) + conn = psycopg.connect(**vars()) logger.info("Postgres is ready! ✨ 💅") conn.close() return True - except psycopg2.OperationalError: + except psycopg.OperationalError: logger.info( f"Postgres isn't ready. Waiting for {check_interval} " f"{interval_unit}..." diff --git a/workplace/admin.py b/workplace/admin.py index a7d13c6a..3f5bd3cd 100644 --- a/workplace/admin.py +++ b/workplace/admin.py @@ -1,6 +1,6 @@ from admin_auto_filters.filters import AutocompleteFilter from django.contrib import admin -from django.utils.translation import ugettext_lazy as _ +from django.utils.translation import gettext_lazy as _ from import_export.admin import ExportActionModelAdmin from modeltranslation.admin import TranslationAdmin from safedelete.admin import SafeDeleteAdmin, highlight_deleted diff --git a/workplace/fields.py b/workplace/fields.py index 5feb7fba..d966ff41 100644 --- a/workplace/fields.py +++ b/workplace/fields.py @@ -2,7 +2,7 @@ from rest_framework import serializers -from django.utils.translation import ugettext_lazy as _ +from django.utils.translation import gettext_lazy as _ class TimezoneField(serializers.CharField): diff --git a/workplace/migrations/0028_historicalperiod_deleted_by_cascade_and_more.py b/workplace/migrations/0028_historicalperiod_deleted_by_cascade_and_more.py new file mode 100644 index 00000000..cf9192bd --- /dev/null +++ b/workplace/migrations/0028_historicalperiod_deleted_by_cascade_and_more.py @@ -0,0 +1,83 @@ +# Generated by Django 4.2.5 on 2023-11-28 18:03 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('workplace', '0027_auto_20230817_0923'), + ] + + operations = [ + migrations.AddField( + model_name='historicalperiod', + name='deleted_by_cascade', + field=models.BooleanField(default=False, editable=False), + ), + migrations.AddField( + model_name='historicalreservation', + name='deleted_by_cascade', + field=models.BooleanField(default=False, editable=False), + ), + migrations.AddField( + model_name='historicalworkplace', + name='deleted_by_cascade', + field=models.BooleanField(default=False, editable=False), + ), + migrations.AddField( + model_name='period', + name='deleted_by_cascade', + field=models.BooleanField(default=False, editable=False), + ), + migrations.AddField( + model_name='reservation', + name='deleted_by_cascade', + field=models.BooleanField(default=False, editable=False), + ), + migrations.AddField( + model_name='timeslot', + name='deleted_by_cascade', + field=models.BooleanField(default=False, editable=False), + ), + migrations.AddField( + model_name='workplace', + name='deleted_by_cascade', + field=models.BooleanField(default=False, editable=False), + ), + migrations.AlterField( + model_name='historicalperiod', + name='deleted', + field=models.DateTimeField(db_index=True, editable=False, null=True), + ), + migrations.AlterField( + model_name='historicalreservation', + name='deleted', + field=models.DateTimeField(db_index=True, editable=False, null=True), + ), + migrations.AlterField( + model_name='historicalworkplace', + name='deleted', + field=models.DateTimeField(db_index=True, editable=False, null=True), + ), + migrations.AlterField( + model_name='period', + name='deleted', + field=models.DateTimeField(db_index=True, editable=False, null=True), + ), + migrations.AlterField( + model_name='reservation', + name='deleted', + field=models.DateTimeField(db_index=True, editable=False, null=True), + ), + migrations.AlterField( + model_name='timeslot', + name='deleted', + field=models.DateTimeField(db_index=True, editable=False, null=True), + ), + migrations.AlterField( + model_name='workplace', + name='deleted', + field=models.DateTimeField(db_index=True, editable=False, null=True), + ), + ] diff --git a/workplace/models.py b/workplace/models.py index 8c7c910f..38af276f 100644 --- a/workplace/models.py +++ b/workplace/models.py @@ -1,5 +1,5 @@ from django.db import models -from django.utils.translation import ugettext_lazy as _ +from django.utils.translation import gettext_lazy as _ from django.utils.html import format_html from django.contrib.auth import get_user_model from django.contrib.contenttypes.models import ContentType diff --git a/workplace/serializers.py b/workplace/serializers.py index c91ef9dd..cf4feb9e 100644 --- a/workplace/serializers.py +++ b/workplace/serializers.py @@ -17,7 +17,7 @@ from django.db.models import F from django.template.loader import render_to_string from django.utils import timezone -from django.utils.translation import ugettext_lazy as _ +from django.utils.translation import gettext_lazy as _ from blitz_api.serializers import UserSerializer from blitz_api.services import (remove_translation_fields, @@ -114,7 +114,7 @@ def to_representation(self, instance): class Meta: model = Workplace - exclude = ('deleted',) + exclude = ('deleted', 'deleted_by_cascade') extra_kwargs = { 'details': {'help_text': _("Description of the workplace.")}, 'name': { @@ -258,7 +258,7 @@ def to_representation(self, instance): class Meta: model = Period - exclude = ('deleted',) + exclude = ('deleted', 'deleted_by_cascade') extra_kwargs = { 'workplace': { 'required': True, @@ -512,7 +512,7 @@ def to_representation(self, instance): class Meta: model = TimeSlot - exclude = ('deleted', 'users') + exclude = ('deleted', 'deleted_by_cascade', 'users') extra_kwargs = { 'period': { 'required': True, @@ -674,7 +674,7 @@ def save(self, **kwargs): class Meta: model = TimeSlot - exclude = ('deleted', 'price', 'users',) + exclude = ('deleted', 'deleted_by_cascade', 'price', 'users',) class ReservationSerializer(serializers.HyperlinkedModelSerializer): @@ -753,7 +753,7 @@ def to_representation(self, instance): class Meta: model = Reservation - exclude = ('deleted',) + exclude = ('deleted', 'deleted_by_cascade') extra_kwargs = { 'is_active': { 'required': True, diff --git a/workplace/views.py b/workplace/views.py index e370819a..d14a23dc 100644 --- a/workplace/views.py +++ b/workplace/views.py @@ -15,7 +15,7 @@ from django.db.models import F, Q from django.template.loader import render_to_string from django.utils import timezone -from django.utils.translation import ugettext_lazy as _ +from django.utils.translation import gettext_lazy as _ from rest_framework.utils import json from blitz_api.mixins import ExportMixin