From 864460853b8ac011016ee8af3494e374c4c23899 Mon Sep 17 00:00:00 2001 From: Olga Komleva Date: Fri, 24 Nov 2023 12:05:22 +0300 Subject: [PATCH] fix incomes if it was rejected, fix adress in draft, filters fo projects/me add in schemas --- backend/api/filters.py | 123 ++++++++++++++++++++++++++----------- backend/api/schemas.py | 8 ++- backend/api/serializers.py | 85 +++++++++++++++++++++---- backend/api/views.py | 47 ++++++++++---- 4 files changed, 202 insertions(+), 61 deletions(-) diff --git a/backend/api/filters.py b/backend/api/filters.py index 2485fd2..2960a29 100644 --- a/backend/api/filters.py +++ b/backend/api/filters.py @@ -108,34 +108,34 @@ class StatusProjectFilter(django_filters.FilterSet): Фильтр статусов для проектов в личном кабинете. Организатор может фильтровать проекты по одному из фильтров: - по фильтру "Черновик" /projects/me/?draft=true - по фильтру "Активен" /projects/me/?active=true - по фильтру "Завершен" /projects/me/?completed=true - по фильтру "Архив" /projects/me/?archive=true. + по фильтру "Черновик" /projects/me/?draft=true, + по фильтру "Активен" /projects/me/?active=true, + по фильтру "Завершен" /projects/me/?completed=true, + по фильтру "Архив" /projects/me/?archive=true, + по фильтру "На модерации" /projects/me/?moderation=true, + по фильтру "Избранное" /projects/me/?is_favorited=true. Волонтер может фильтровать проекты по одному из фильтров: - по фильтру "Активен" /projects/me/?active=true - по фильтру "Завершен" /projects/me/?completed=true. - по фильтру "На модерации" /projects/me/?moderation=true. + по фильтру "Активен" /projects/me/?active=true, + по фильтру "Завершен" /projects/me/?completed=true, + по фильтру "Отменен" /projects/me/?archive=true, + по фильтру "Избранное" /projects/me/?is_favorited=true. """ - draft = django_filters.CharFilter(method='filter_draft') - active = django_filters.CharFilter(method='filter_active') - completed = django_filters.CharFilter(method='filter_completed') - archive = django_filters.CharFilter(method='filter_archive') - moderation = django_filters.CharFilter(method='filter_moderation') + # draft = django_filters.CharFilter(method='filter_draft') + # active = django_filters.CharFilter(method='filter_active') + # completed = django_filters.CharFilter(method='filter_completed') + # archive = django_filters.CharFilter(method='filter_archive') + # moderation = django_filters.CharFilter(method='filter_moderation') + # is_favorited = django_filters.CharFilter(method='filter_is_favorited') def filter_draft(self, queryset): """ Фильтр для таба "Черновик". """ return queryset.filter( - Q( - status_approve__in=[ - Project.EDITING, - Project.REJECTED, - ] - ) + Q(status_approve__in=[Project.EDITING, Project.REJECTED,]), + organization__contact_person=self.request.user ) def filter_active(self, queryset): @@ -144,7 +144,8 @@ def filter_active(self, queryset): """ now = timezone.now() return queryset.filter( - Q(status_approve=Project.APPROVED), end_datetime__gt=now + Q(status_approve=Project.APPROVED), end_datetime__gt=now, + organization__contact_person=self.request.user ) def filter_completed(self, queryset): @@ -153,7 +154,8 @@ def filter_completed(self, queryset): """ now = timezone.now() return queryset.filter( - Q(status_approve=Project.APPROVED), end_datetime__lte=now + Q(status_approve=Project.APPROVED), end_datetime__lte=now, + organization__contact_person=self.request.user ) def filter_archive(self, queryset): @@ -161,14 +163,58 @@ def filter_archive(self, queryset): Фильтр для таба "Архив". """ - return queryset.filter(Q(status_approve=Project.CANCELED_BY_ORGANIZER)) + return queryset.filter( + Q(status_approve=Project.CANCELED_BY_ORGANIZER), + organization__contact_person=self.request.user + ) def filter_moderation(self, queryset): """ Фильтр для таба "На модерации". """ - return queryset.filter(Q(status_approve=Project.PENDING)) + return queryset.filter( + Q(status_approve=Project.PENDING), + organization__contact_person=self.request.user + ) + + def filter_is_favorited(self, queryset): + """ + Фильтр для таба "Избранные". + """ + + return queryset.filter(Q(project_favorite__user=self.request.user)) + + def filter_active_volunteer(self, queryset): + """ + Фильтр для таба "Активен". + """ + now = timezone.now() + return queryset.filter( + Q(status_approve=Project.APPROVED), end_datetime__gt=now, + participants__volunteer=self.request.user.volunteers + ) + + def filter_completed_volunteer(self, queryset): + """ + Фильтр для таба "Завершен". + """ + now = timezone.now() + return queryset.filter( + Q(status_approve=Project.APPROVED), end_datetime__lte=now, + participants__volunteer=self.request.user.volunteers + ) + + # def filter_canseled(self, queryset): + def filter_archive_volunteer(self, queryset): + """ + Фильтр для таба "Архив". + """ + + return queryset.filter( + Q(status_approve=Project.CANCELED_BY_ORGANIZER), + participants__volunteer=self.request.user.volunteers + ) # TODO фильтры по статусам проекта в ЛК Волонтера # Простой код для понимания и дополнения статусов волнтеров @@ -196,27 +242,30 @@ def filter_queryset(self, queryset): if user.is_organizer: status_filter = ( - self.data.get("draft") - and self.filter_draft - or self.data.get("active") - and self.filter_active - or self.data.get("completed") - and self.filter_completed - or self.data.get("archive") - and self.filter_archive - or self.data.get("moderation") - and self.filter_moderation + self.data.get('draft') and self.filter_draft + or self.data.get('active') and self.filter_active + or self.data.get('completed') and self.filter_completed + or self.data.get('archive') and self.filter_archive + or self.data.get('moderation') and self.filter_moderation + or self.data.get('is_favorited') and self.filter_is_favorited ) elif user.is_volunteer: status_filter = ( - self.data.get("active") - and self.filter_active - or self.data.get("completed") - and self.filter_completed + self.data.get('active') + # and self.filter_active + and self.filter_active_volunteer + or self.data.get('completed') + # and self.filter_completed + and self.filter_completed_volunteer + or self.data.get('archive') + and self.filter_archive_volunteer + # and self.filter_canseled + or self.data.get('is_favorited') + and self.filter_is_favorited ) if status_filter: - queryset = status_filter(queryset) + queryset = status_filter(queryset).distinct() return queryset diff --git a/backend/api/schemas.py b/backend/api/schemas.py index 2cf5251..5cdabc3 100644 --- a/backend/api/schemas.py +++ b/backend/api/schemas.py @@ -19,7 +19,8 @@ ), openapi.Parameter( 'archive', openapi.IN_QUERY, type=openapi.TYPE_STRING, - description=('Фильтрует проекты организатора в архиве. ' + description=('Фильтрует проекты организатора/волонтера в архиве' + '(отменненые организатором). ' 'Пример запроса /projects/me/?archive=true') ), openapi.Parameter( @@ -27,4 +28,9 @@ description=('Фильтрует проекты организатора на модерации. ' 'Пример запроса /projects/me/?moderation=true') ), + openapi.Parameter( + 'is_favorited', openapi.IN_QUERY, type=openapi.TYPE_STRING, + description=('Фильтрует избранные проекты организатора/волонтера. ' + 'Пример запроса /projects/me/?is_favorited=true') + ), ] diff --git a/backend/api/serializers.py b/backend/api/serializers.py index 3b3b090..c1c9274 100644 --- a/backend/api/serializers.py +++ b/backend/api/serializers.py @@ -76,7 +76,7 @@ class Meta: ) def get_projects_count(self, obj): - return Project.objects.count() + return Project.objects.filter(status_approve=Project.APPROVED).count() def get_volunteers_count(self, obj): return Volunteer.objects.count() @@ -263,11 +263,23 @@ def validate_status_approve(self, value): ) return value - def create(self, validated_data): - project_instance = super().create(validated_data) - project_instance.status_approve = Project.EDITING - project_instance.save() + # def create(self, validated_data): + # project_instance = super().create(validated_data) + # project_instance.status_approve = Project.EDITING + # project_instance.save() + + # return project_instance + def create(self, validated_data): + address_data = validated_data.pop('event_address', None) + with transaction.atomic(): + project_instance = super().create(validated_data) + project_instance.status_approve = Project.EDITING + project_instance.save() + if address_data: + address, _ = Address.objects.get_or_create(**address_data) + project_instance.event_address = address + project_instance.save() return project_instance def update(self, instance, validated_data): @@ -603,6 +615,9 @@ class Meta: 'volunteer', 'status_incomes', 'created_at', + 'phone', + 'telegram', + 'cover_letter', ) @@ -623,25 +638,73 @@ class Meta: 'cover_letter', 'created_at', ) - read_only_fields = ('id', 'created_at') + # read_only_fields = ('id', 'created_at') + read_only_fields = ('id', 'created_at', 'volunteer') + + # def create(self, validated_data): + # """ + # Создает заявку волонтера. + # """ + # project = validated_data['project'] + # volunteer = validated_data['volunteer'] + # status_incomes = validated_data.get( + # 'status_incomes', ProjectIncomes.APPLICATION_SUBMITTED + # ) + # # if ( + # # ProjectIncomes.objects.filter(project=project, volunteer=volunteer) + # # .exclude(status_incomes=ProjectIncomes.REJECTED) + # # .exists() + # # ): + # # проверить работу чере релейтед нейм + # if ( + # project.project_incomes.filter(volunteer=volunteer) + # .exclude(status_incomes=ProjectIncomes.REJECTED).exists() + # ): + # raise serializers.ValidationError( + # 'Заявка волонтера на этот проект уже существует.' + # ) + # if (project.project_incomes.filter( + # volunteer=volunteer, status_incomes=ProjectIncomes.REJECTED + # ).exists() + # ): + # raise serializers.ValidationError( + # 'Вы не можете повторно подать завку, ваша заявка ранее была отклонена' + # ) + # project_income = ProjectIncomes.objects.create( + # project=project, + # volunteer=volunteer, + # status_incomes=status_incomes, + # phone=validated_data.get('phone', ''), + # telegram=validated_data.get('telegram', ''), + # cover_letter=validated_data.get('cover_letter', ''), + # ) + # return project_income def create(self, validated_data): """ Создает заявку волонтера. """ project = validated_data['project'] - volunteer = validated_data['volunteer'] + volunteer = self.context['request'].user.volunteers status_incomes = validated_data.get( 'status_incomes', ProjectIncomes.APPLICATION_SUBMITTED ) if ( - ProjectIncomes.objects.filter(project=project, volunteer=volunteer) - .exclude(status_incomes=ProjectIncomes.REJECTED) - .exists() + project.project_incomes.filter(volunteer=volunteer) + .exclude(status_incomes=ProjectIncomes.REJECTED).exists() ): raise serializers.ValidationError( 'Заявка волонтера на этот проект уже существует.' ) + if ( + project.project_incomes.filter( + volunteer=volunteer, status_incomes=ProjectIncomes.REJECTED + ).exists() + ): + raise serializers.ValidationError( + 'Вы не можете повторно подать завку, ' + 'ваша заявка ранее была отклонена' + ) project_income = ProjectIncomes.objects.create( project=project, volunteer=volunteer, @@ -712,7 +775,7 @@ def to_representation(self, instance): if user.role == User.ORGANIZER: return super().to_representation(instance) data = super().to_representation(instance) - data['volunteer'] = {'id': instance.volunteer.id} + # data['volunteer'] = {'id': instance.volunteer.id} return data diff --git a/backend/api/views.py b/backend/api/views.py index 302edf6..77ee160 100644 --- a/backend/api/views.py +++ b/backend/api/views.py @@ -1,4 +1,4 @@ -from django.db.models import Exists, OuterRef, Q +from django.db.models import Q # Exists, OuterRef, from django.shortcuts import get_object_or_404 from django.utils import timezone from django_filters.rest_framework import DjangoFilterBackend @@ -518,6 +518,9 @@ def get_permissions(self): self.action, [IsOrganizerOfProject] ) return [permission() for permission in permission_classes] + # добавлено попытка создать пользователя + # def perform_create(self, serializer): + # serializer.save(volunteer=self.request.user.volunteers) @action( detail=True, @@ -593,23 +596,43 @@ class ProjectMeViewSet(viewsets.GenericViewSet, mixins.ListModelMixin): def get_queryset(self): if self.request.user.is_volunteer: - volunteer = get_object_or_404(Volunteer, user=self.request.user.id) - from_volunteer_favorite = ProjectFavorite.objects.filter( - project=OuterRef('pk'), volunteer=volunteer + # volunteer = get_object_or_404(Volunteer, user=self.request.user.id) + # from_volunteer_favorite = ProjectFavorite.objects.filter( + # project=OuterRef('pk'), volunteer=volunteer + # ) + # return ( + # Project.objects.filter(participant__volunteer=volunteer) + # # .select_related('organization') + # # .prefetch_related('categories', 'skills') + # .annotate( + # is_favorited=Exists(from_volunteer_favorite), + # ) + # ) + + # volunteer = Volunteer.objects.get(user=self.request.user) + volunteer = self.request.user.volunteers + volunteer_in_projects = Project.objects.filter( + participants__volunteer=volunteer ) - return ( - Project.objects.filter(participant__volunteer=volunteer) - # .select_related('organization') - # .prefetch_related('categories', 'skills') - .annotate( - is_favorited=Exists(from_volunteer_favorite), - ) + favorite_projects = Project.objects.filter( + Q(project_favorite__user=self.request.user) ) + return (favorite_projects | volunteer_in_projects).distinct() + + # if self.request.user.is_organizer: + # return Project.objects.filter( + # organization__contact_person=self.request.user + # ) if self.request.user.is_organizer: - return Project.objects.filter( + favorite_projects = Project.objects.filter( + Q(project_favorite__user=self.request.user) + ) + organizer_projects = Project.objects.filter( organization__contact_person=self.request.user ) + return (favorite_projects | organizer_projects).distinct() + # organization = get_object_or_404( # Organization, # contact_person=self.request.user.id