|
1 | 1 | from django.contrib.auth import get_user_model |
2 | 2 | from django.db import IntegrityError, transaction |
| 3 | +from django.shortcuts import get_object_or_404 |
3 | 4 | from django.utils import timezone |
4 | 5 | from django.utils.timezone import now |
5 | 6 | from drf_yasg import openapi |
|
16 | 17 | from partner_programs.helpers import date_to_iso |
17 | 18 | from partner_programs.models import ( |
18 | 19 | PartnerProgram, |
| 20 | + PartnerProgramField, |
19 | 21 | PartnerProgramFieldValue, |
20 | 22 | PartnerProgramProject, |
21 | 23 | PartnerProgramUserProfile, |
|
24 | 26 | from partner_programs.permissions import IsProjectLeader |
25 | 27 | from partner_programs.serializers import ( |
26 | 28 | PartnerProgramDataSchemaSerializer, |
| 29 | + PartnerProgramFieldSerializer, |
27 | 30 | PartnerProgramForMemberSerializer, |
28 | 31 | PartnerProgramForUnregisteredUserSerializer, |
29 | 32 | PartnerProgramListSerializer, |
30 | 33 | PartnerProgramNewUserSerializer, |
31 | 34 | PartnerProgramUserSerializer, |
| 35 | + ProgramProjectFilterRequestSerializer, |
32 | 36 | ) |
| 37 | +from partner_programs.utils import filter_program_projects_by_field_name |
33 | 38 | from projects.models import Project |
34 | | -from projects.serializers import PartnerProgramFieldValueUpdateSerializer |
| 39 | +from projects.serializers import ( |
| 40 | + PartnerProgramFieldValueUpdateSerializer, |
| 41 | + ProjectListSerializer, |
| 42 | +) |
35 | 43 | from vacancy.mapping import ( |
36 | 44 | MessageTypeEnum, |
37 | 45 | UserProgramRegisterParams, |
@@ -341,3 +349,78 @@ def post(self, request, pk, *args, **kwargs): |
341 | 349 | {"detail": "Проект успешно сдан на проверку."}, |
342 | 350 | status=status.HTTP_200_OK, |
343 | 351 | ) |
| 352 | + |
| 353 | + |
| 354 | +class ProgramFiltersAPIView(APIView): |
| 355 | + permission_classes = [permissions.IsAuthenticated] |
| 356 | + |
| 357 | + def get(self, request, pk): |
| 358 | + program = get_object_or_404(PartnerProgram, pk=pk) |
| 359 | + fields = PartnerProgramField.objects.filter( |
| 360 | + partner_program=program, show_filter=True |
| 361 | + ) |
| 362 | + serializer = PartnerProgramFieldSerializer(fields, many=True) |
| 363 | + return Response(serializer.data) |
| 364 | + |
| 365 | + |
| 366 | +class ProgramProjectFilterAPIView(GenericAPIView): |
| 367 | + serializer_class = ProgramProjectFilterRequestSerializer |
| 368 | + permission_classes = [permissions.IsAuthenticated] |
| 369 | + pagination_class = PartnerProgramPagination |
| 370 | + |
| 371 | + def post(self, request, pk): |
| 372 | + serializer = self.get_serializer(data=request.data) |
| 373 | + serializer.is_valid(raise_exception=True) |
| 374 | + data = serializer.validated_data |
| 375 | + |
| 376 | + program = get_object_or_404(PartnerProgram, pk=pk) |
| 377 | + filters = data.get("filters", {}) |
| 378 | + |
| 379 | + field_names = list(filters.keys()) |
| 380 | + field_qs = PartnerProgramField.objects.filter( |
| 381 | + partner_program=program, name__in=field_names |
| 382 | + ) |
| 383 | + field_by_name = {f.name: f for f in field_qs} |
| 384 | + |
| 385 | + missing = [name for name in field_names if name not in field_by_name] |
| 386 | + if missing: |
| 387 | + return Response( |
| 388 | + {"detail": f"Поля не найденные в программе: {missing}"}, |
| 389 | + status=status.HTTP_400_BAD_REQUEST, |
| 390 | + ) |
| 391 | + |
| 392 | + for field_name, values in filters.items(): |
| 393 | + field_obj = field_by_name[field_name] |
| 394 | + if not field_obj.show_filter: |
| 395 | + return Response( |
| 396 | + { |
| 397 | + "detail": f"Поле '{field_name}' недоступно для фильтрации (show_filter=False)." |
| 398 | + }, |
| 399 | + status=status.HTTP_400_BAD_REQUEST, |
| 400 | + ) |
| 401 | + opts = field_obj.get_options_list() |
| 402 | + if opts: |
| 403 | + invalid_values = [val for val in values if val not in opts] |
| 404 | + if invalid_values: |
| 405 | + return Response( |
| 406 | + { |
| 407 | + "detail": f"Неверные значения для поля '{field_name}'.", |
| 408 | + "invalid": invalid_values, |
| 409 | + }, |
| 410 | + status=status.HTTP_400_BAD_REQUEST, |
| 411 | + ) |
| 412 | + else: |
| 413 | + return Response( |
| 414 | + {"detail": f"Поле '{field_name}' не имеет вариантов (options)."}, |
| 415 | + status=status.HTTP_400_BAD_REQUEST, |
| 416 | + ) |
| 417 | + |
| 418 | + qs = filter_program_projects_by_field_name(program, filters) |
| 419 | + |
| 420 | + paginator = self.pagination_class() |
| 421 | + page = paginator.paginate_queryset(qs, request, view=self) |
| 422 | + projects = [pp.project for pp in page] |
| 423 | + serializer_out = ProjectListSerializer( |
| 424 | + projects, many=True, context={"request": request} |
| 425 | + ) |
| 426 | + return paginator.get_paginated_response(serializer_out.data) |
0 commit comments