From 33430af6520ea8270f1904d2f05faa44dda791b4 Mon Sep 17 00:00:00 2001 From: magsyg Date: Tue, 5 Nov 2024 23:02:13 +0100 Subject: [PATCH 1/8] feat: make fetching and organized applicants by state to backend --- backend/root/utils/routes.py | 2 + backend/samfundet/serializers.py | 31 ++++++++ backend/samfundet/urls.py | 5 ++ backend/samfundet/views.py | 20 +++-- .../RecruitmentPositionOverviewPage.tsx | 76 ++++--------------- frontend/src/api.ts | 17 ++++- frontend/src/dto.ts | 8 ++ frontend/src/routes/backend.ts | 2 + 8 files changed, 91 insertions(+), 70 deletions(-) diff --git a/backend/root/utils/routes.py b/backend/root/utils/routes.py index 74cc0fc7e..54672e72e 100644 --- a/backend/root/utils/routes.py +++ b/backend/root/utils/routes.py @@ -564,6 +564,7 @@ samfundet__interview_list = 'samfundet:interview-list' samfundet__interview_detail = 'samfundet:interview-detail' samfundet__api_root = 'samfundet:api-root' +samfundet__api_root = 'samfundet:api-root' samfundet__schema = 'samfundet:schema' samfundet__swagger_ui = 'samfundet:swagger_ui' samfundet__redoc = 'samfundet:redoc' @@ -591,6 +592,7 @@ samfundet__recruitment_set_interview = 'samfundet:recruitment_set_interview' samfundet__recruitment_application_states_choices = 'samfundet:recruitment_application_states_choices' samfundet__recruitment_application_update_state_gang = 'samfundet:recruitment_application_update_state_gang' +samfundet__recruitment_position_organized_applications = 'samfundet:recruitment_position_organized_applications' samfundet__recruitment_application_update_state_position = 'samfundet:recruitment_application_update_state_position' samfundet__recruitment_applications_recruiter = 'samfundet:recruitment_applications_recruiter' samfundet__recruitment_withdraw_application = 'samfundet:recruitment_withdraw_application' diff --git a/backend/samfundet/serializers.py b/backend/samfundet/serializers.py index 3e8488380..96bb7f5b5 100644 --- a/backend/samfundet/serializers.py +++ b/backend/samfundet/serializers.py @@ -1094,6 +1094,37 @@ def update(self, instance: RecruitmentApplication, validated_data: dict) -> Recr def get_application_count(self, application: RecruitmentApplication) -> int: return application.user.applications.filter(recruitment=application.recruitment).count() +class RecruitmentPositionOrganizedApplications(CustomBaseSerializer): + applicationSerializer = RecruitmentApplicationForGangSerializer + unprocessed = serializers.SerializerMethodField(method_name='get_unprocessed', read_only=True) + withdrawn = serializers.SerializerMethodField(method_name='get_withdrawn', read_only=True) + accepted = serializers.SerializerMethodField(method_name='get_accepted', read_only=True) + rejected = serializers.SerializerMethodField(method_name='get_rejected', read_only=True) + hardtoget = serializers.SerializerMethodField(method_name='get_hardtoget', read_only=True) + + class Meta: + model = RecruitmentPosition + fields = ['unprocessed', 'withdrawn', 'accepted', 'rejected', 'hardtoget'] + + def get_unprocessed(self, instance: RecruitmentPosition): + unprocessed = instance.applications.filter(withdrawn=False, recruiter_status=RecruitmentStatusChoices.NOT_SET) + return self.applicationSerializer(unprocessed, many=True).data + + def get_withdrawn(self, instance: RecruitmentPosition): + withdrawn = instance.applications.filter(withdrawn=True) + return self.applicationSerializer(withdrawn, many=True).data + + def get_rejected(self, instance: RecruitmentPosition): + rejected = instance.applications.filter(withdrawn=False, recruiter_status__in=[RecruitmentStatusChoices.AUTOMATIC_REJECTION, RecruitmentStatusChoices.REJECTION]) + return self.applicationSerializer(rejected, many=True).data + + def get_accepted(self, instance: RecruitmentPosition): + accepted = instance.applications.filter(withdrawn=False, recruiter_status=RecruitmentStatusChoices.CALLED_AND_ACCEPTED) + return self.applicationSerializer(accepted, many=True).data + + def get_hardtoget(self, instance: RecruitmentPosition): + hardtoget = instance.applications.filter(withdrawn=False, recruiter_status=RecruitmentStatusChoices.CALLED_AND_REJECTED) + return self.applicationSerializer(hardtoget, many=True).data class RecruitmentApplicationUpdateForGangSerializer(serializers.Serializer): recruiter_priority = serializers.ChoiceField(choices=RecruitmentPriorityChoices.choices, required=False) diff --git a/backend/samfundet/urls.py b/backend/samfundet/urls.py index 3761d75c3..3bcda7a60 100644 --- a/backend/samfundet/urls.py +++ b/backend/samfundet/urls.py @@ -105,6 +105,11 @@ views.RecruitmentApplicationForGangUpdateStateView.as_view(), name='recruitment_application_update_state_gang', ), + path( + 'recruitment-position-organized-applications//', + views.RecruitmentPositionOrganizedApplicationsView.as_view(), + name='recruitment_position_organized_applications', + ), path( 'recruitment-application-update-state-position//', views.RecruitmentApplicationForPositionUpdateStateView.as_view(), diff --git a/backend/samfundet/views.py b/backend/samfundet/views.py index 875f80229..9287a0bbb 100644 --- a/backend/samfundet/views.py +++ b/backend/samfundet/views.py @@ -42,6 +42,7 @@ from .homepage import homepage from .models.role import Role from .serializers import ( + RecruitmentPositionOrganizedApplications, TagSerializer, GangSerializer, MenuSerializer, @@ -1043,13 +1044,21 @@ def put(self, request: Request, pk: int) -> Response: return Response(update_serializer.errors, status=status.HTTP_400_BAD_REQUEST) +class RecruitmentPositionOrganizedApplicationsView(APIView): + permission_classes = [IsAuthenticated] + serializer_class = RecruitmentPositionOrganizedApplications + + def get(self, request: Request, pk: int) -> Response: + position = get_object_or_404(RecruitmentPosition, pk=pk) + serializer = self.serializer_class(position) + return Response(serializer.data, status=status.HTTP_200_OK) + class RecruitmentApplicationForPositionUpdateStateView(APIView): permission_classes = [IsAuthenticated] serializer_class = RecruitmentApplicationUpdateForGangSerializer def put(self, request: Request, pk: int) -> Response: application = get_object_or_404(RecruitmentApplication, pk=pk) - # TODO add check if user has permission to update for GANG update_serializer = self.serializer_class(data=request.data) if update_serializer.is_valid(): @@ -1060,12 +1069,9 @@ def put(self, request: Request, pk: int) -> Response: application.recruiter_status = update_serializer.data['recruiter_status'] application.save() application.update_applicant_state() - applications = RecruitmentApplication.objects.filter( - recruitment_position=application.recruitment_position, # Only change from above - recruitment=application.recruitment, - ) - serializer = RecruitmentApplicationForGangSerializer(applications, many=True) - return Response(serializer.data, status=status.HTTP_200_OK) + position = get_object_or_404(RecruitmentPosition, pk=application.recruitment_position.id) + organized_serializer = RecruitmentPositionOrganizedApplications(position) + return Response(organized_serializer.data, status=status.HTTP_200_OK) return Response(update_serializer.errors, status=status.HTTP_400_BAD_REQUEST) diff --git a/frontend/src/PagesAdmin/RecruitmentPositionOverviewPage/RecruitmentPositionOverviewPage.tsx b/frontend/src/PagesAdmin/RecruitmentPositionOverviewPage/RecruitmentPositionOverviewPage.tsx index 9d90f823c..3af1c196c 100644 --- a/frontend/src/PagesAdmin/RecruitmentPositionOverviewPage/RecruitmentPositionOverviewPage.tsx +++ b/frontend/src/PagesAdmin/RecruitmentPositionOverviewPage/RecruitmentPositionOverviewPage.tsx @@ -4,7 +4,7 @@ import { useNavigate, useParams } from 'react-router-dom'; import { toast } from 'react-toastify'; import { Button, RecruitmentApplicantsStatus } from '~/Components'; import { Text } from '~/Components/Text/Text'; -import { getRecruitmentApplicationsForGang, updateRecruitmentApplicationStateForPosition } from '~/api'; +import { getRecruitmentApplicationsForGang, getRecruitmentPositionOrganizedApplications, updateRecruitmentApplicationStateForPosition } from '~/api'; import type { RecruitmentApplicationDto, RecruitmentApplicationStateDto } from '~/dto'; import { useTitle } from '~/hooks'; import { STATUS } from '~/http_status_codes'; @@ -33,46 +33,22 @@ export function RecruitmentPositionOverviewPage() { if (!recruitmentId || !gangId || !positionId) { return; } - getRecruitmentApplicationsForGang(gangId, recruitmentId) - .then((data) => { + getRecruitmentPositionOrganizedApplications(positionId) + .then((response) => { setRecruitmentApplicants( - data.data.filter( - (recruitmentApplicant) => - !recruitmentApplicant.withdrawn && - recruitmentApplicant.recruiter_status === 0 && - recruitmentApplicant.recruitment_position?.id === Number.parseInt(positionId), - ), + response.data.unprocessed ); setWithdrawnApplicants( - data.data.filter( - (recruitmentApplicant) => - recruitmentApplicant.withdrawn && - recruitmentApplicant.recruitment_position?.id === Number.parseInt(positionId), - ), + response.data.withdrawn ); setHardtogetApplicants( - data.data.filter( - (recruitmentApplicant) => - !recruitmentApplicant.withdrawn && - recruitmentApplicant.recruiter_status === 2 && - recruitmentApplicant.recruitment_position?.id === Number.parseInt(positionId), - ), + response.data.hardtoget ); setRejectedApplicants( - data.data.filter( - (recruitmentApplicant) => - !recruitmentApplicant.withdrawn && - recruitmentApplicant.recruiter_status === 3 && - recruitmentApplicant.recruitment_position?.id === Number.parseInt(positionId), - ), + response.data.rejected ); setAcceptedApplicants( - data.data.filter( - (recruitmentApplicant) => - !recruitmentApplicant.withdrawn && - recruitmentApplicant.recruiter_status === 1 && - recruitmentApplicant.recruitment_position?.id === Number.parseInt(positionId), - ), + response.data.accepted ); setShowSpinner(false); }) @@ -91,45 +67,21 @@ export function RecruitmentPositionOverviewPage() { const updateApplicationState = (id: string, data: RecruitmentApplicationStateDto) => { positionId && updateRecruitmentApplicationStateForPosition(id, data) - .then((data) => { + .then((response) => { setRecruitmentApplicants( - data.data.filter( - (recruitmentApplicant) => - !recruitmentApplicant.withdrawn && - recruitmentApplicant.recruiter_status === 0 && - recruitmentApplicant.recruitment_position?.id === Number.parseInt(positionId), - ), + response.data.unprocessed ); setWithdrawnApplicants( - data.data.filter( - (recruitmentApplicant) => - recruitmentApplicant.withdrawn && - recruitmentApplicant.recruitment_position?.id === Number.parseInt(positionId), - ), + response.data.withdrawn ); setHardtogetApplicants( - data.data.filter( - (recruitmentApplicant) => - !recruitmentApplicant.withdrawn && - recruitmentApplicant.recruiter_status === 2 && - recruitmentApplicant.recruitment_position?.id === Number.parseInt(positionId), - ), + response.data.hardtoget ); setRejectedApplicants( - data.data.filter( - (recruitmentApplicant) => - !recruitmentApplicant.withdrawn && - recruitmentApplicant.recruiter_status === 3 && - recruitmentApplicant.recruitment_position?.id === Number.parseInt(positionId), - ), + response.data.rejected ); setAcceptedApplicants( - data.data.filter( - (recruitmentApplicant) => - !recruitmentApplicant.withdrawn && - recruitmentApplicant.recruiter_status === 1 && - recruitmentApplicant.recruitment_position?.id === Number.parseInt(positionId), - ), + response.data.accepted ); setShowSpinner(false); }) diff --git a/frontend/src/api.ts b/frontend/src/api.ts index 9a7997519..dae569074 100644 --- a/frontend/src/api.ts +++ b/frontend/src/api.ts @@ -30,6 +30,7 @@ import type { RecruitmentDto, RecruitmentGangDto, RecruitmentPositionDto, + RecruitmentPositionOrganizedApplicationsDto, RecruitmentPositionPostDto, RecruitmentPositionPutDto, RecruitmentSeparatePositionDto, @@ -819,6 +820,20 @@ export async function getRecruitmentApplicationsForGang( return await axios.get(url, { withCredentials: true }); } +export async function getRecruitmentPositionOrganizedApplications( + positionId: string, +): Promise> { + const url = + BACKEND_DOMAIN + + reverse({ + pattern: ROUTES.backend.samfundet__recruitment_position_organized_applications, + urlParams: { + pk: positionId + }, + }); + return await axios.get(url, { withCredentials: true }); +} + export async function getRecruitmentSharedInterviewGroups( recruitmentId: string, ): Promise> { @@ -888,7 +903,7 @@ export async function updateRecruitmentApplicationStateForGang( export async function updateRecruitmentApplicationStateForPosition( applicationId: string, application: Partial, -): Promise> { +): Promise> { const url = BACKEND_DOMAIN + reverse({ diff --git a/frontend/src/dto.ts b/frontend/src/dto.ts index 4cd54cb1c..53d9da5e2 100644 --- a/frontend/src/dto.ts +++ b/frontend/src/dto.ts @@ -496,6 +496,14 @@ export type InterviewDto = { interviewers?: UserDto[]; }; +export type RecruitmentPositionOrganizedApplicationsDto = { + unprocessed: RecruitmentApplicationDto[]; + withdrawn: RecruitmentApplicationDto[]; + rejected: RecruitmentApplicationDto[]; + accepted: RecruitmentApplicationDto[]; + hardtoget: RecruitmentApplicationDto[]; +} + export type RecruitmentApplicationDto = { id: string; interview?: InterviewDto; diff --git a/frontend/src/routes/backend.ts b/frontend/src/routes/backend.ts index f1b8b9b81..5ca8ce229 100644 --- a/frontend/src/routes/backend.ts +++ b/frontend/src/routes/backend.ts @@ -563,6 +563,7 @@ export const ROUTES_BACKEND = { samfundet__interview_list: '/api/interview/', samfundet__interview_detail: '/api/interview/:pk/', samfundet__api_root: '/api/', + samfundet__api_root: '/api/:format', samfundet__schema: '/schema/', samfundet__swagger_ui: '/schema/swagger-ui/', samfundet__redoc: '/schema/redoc/', @@ -590,6 +591,7 @@ export const ROUTES_BACKEND = { samfundet__recruitment_set_interview: '/recruitment-set-interview/:pk/', samfundet__recruitment_application_states_choices: '/recruitment-application-states-choices', samfundet__recruitment_application_update_state_gang: '/recruitment-application-update-state-gang/:pk/', + samfundet__recruitment_position_organized_applications: '/recruitment-position-organized-applications/:pk/', samfundet__recruitment_application_update_state_position: '/recruitment-application-update-state-position/:pk/', samfundet__recruitment_applications_recruiter: '/recruitment-application-recruiter/:applicationId/', samfundet__recruitment_withdraw_application: '/recruitment-withdraw-application/:pk/', From 8712910c6f8fecb0a465273b306befff84de07a2 Mon Sep 17 00:00:00 2001 From: magsyg Date: Tue, 5 Nov 2024 23:03:06 +0100 Subject: [PATCH 2/8] fix formating --- backend/samfundet/serializers.py | 10 ++-- backend/samfundet/views.py | 1 + .../RecruitmentPositionOverviewPage.tsx | 46 ++++++------------- frontend/src/api.ts | 2 +- frontend/src/dto.ts | 2 +- 5 files changed, 25 insertions(+), 36 deletions(-) diff --git a/backend/samfundet/serializers.py b/backend/samfundet/serializers.py index 96bb7f5b5..ec2e05019 100644 --- a/backend/samfundet/serializers.py +++ b/backend/samfundet/serializers.py @@ -1094,6 +1094,7 @@ def update(self, instance: RecruitmentApplication, validated_data: dict) -> Recr def get_application_count(self, application: RecruitmentApplication) -> int: return application.user.applications.filter(recruitment=application.recruitment).count() + class RecruitmentPositionOrganizedApplications(CustomBaseSerializer): applicationSerializer = RecruitmentApplicationForGangSerializer unprocessed = serializers.SerializerMethodField(method_name='get_unprocessed', read_only=True) @@ -1113,19 +1114,22 @@ def get_unprocessed(self, instance: RecruitmentPosition): def get_withdrawn(self, instance: RecruitmentPosition): withdrawn = instance.applications.filter(withdrawn=True) return self.applicationSerializer(withdrawn, many=True).data - + def get_rejected(self, instance: RecruitmentPosition): - rejected = instance.applications.filter(withdrawn=False, recruiter_status__in=[RecruitmentStatusChoices.AUTOMATIC_REJECTION, RecruitmentStatusChoices.REJECTION]) + rejected = instance.applications.filter( + withdrawn=False, recruiter_status__in=[RecruitmentStatusChoices.AUTOMATIC_REJECTION, RecruitmentStatusChoices.REJECTION] + ) return self.applicationSerializer(rejected, many=True).data def get_accepted(self, instance: RecruitmentPosition): accepted = instance.applications.filter(withdrawn=False, recruiter_status=RecruitmentStatusChoices.CALLED_AND_ACCEPTED) return self.applicationSerializer(accepted, many=True).data - + def get_hardtoget(self, instance: RecruitmentPosition): hardtoget = instance.applications.filter(withdrawn=False, recruiter_status=RecruitmentStatusChoices.CALLED_AND_REJECTED) return self.applicationSerializer(hardtoget, many=True).data + class RecruitmentApplicationUpdateForGangSerializer(serializers.Serializer): recruiter_priority = serializers.ChoiceField(choices=RecruitmentPriorityChoices.choices, required=False) recruiter_status = serializers.ChoiceField(choices=RecruitmentStatusChoices.choices, required=False) diff --git a/backend/samfundet/views.py b/backend/samfundet/views.py index 9287a0bbb..f9ae11a69 100644 --- a/backend/samfundet/views.py +++ b/backend/samfundet/views.py @@ -1053,6 +1053,7 @@ def get(self, request: Request, pk: int) -> Response: serializer = self.serializer_class(position) return Response(serializer.data, status=status.HTTP_200_OK) + class RecruitmentApplicationForPositionUpdateStateView(APIView): permission_classes = [IsAuthenticated] serializer_class = RecruitmentApplicationUpdateForGangSerializer diff --git a/frontend/src/PagesAdmin/RecruitmentPositionOverviewPage/RecruitmentPositionOverviewPage.tsx b/frontend/src/PagesAdmin/RecruitmentPositionOverviewPage/RecruitmentPositionOverviewPage.tsx index 3af1c196c..3f37b74e4 100644 --- a/frontend/src/PagesAdmin/RecruitmentPositionOverviewPage/RecruitmentPositionOverviewPage.tsx +++ b/frontend/src/PagesAdmin/RecruitmentPositionOverviewPage/RecruitmentPositionOverviewPage.tsx @@ -4,7 +4,11 @@ import { useNavigate, useParams } from 'react-router-dom'; import { toast } from 'react-toastify'; import { Button, RecruitmentApplicantsStatus } from '~/Components'; import { Text } from '~/Components/Text/Text'; -import { getRecruitmentApplicationsForGang, getRecruitmentPositionOrganizedApplications, updateRecruitmentApplicationStateForPosition } from '~/api'; +import { + getRecruitmentApplicationsForGang, + getRecruitmentPositionOrganizedApplications, + updateRecruitmentApplicationStateForPosition, +} from '~/api'; import type { RecruitmentApplicationDto, RecruitmentApplicationStateDto } from '~/dto'; import { useTitle } from '~/hooks'; import { STATUS } from '~/http_status_codes'; @@ -35,21 +39,11 @@ export function RecruitmentPositionOverviewPage() { } getRecruitmentPositionOrganizedApplications(positionId) .then((response) => { - setRecruitmentApplicants( - response.data.unprocessed - ); - setWithdrawnApplicants( - response.data.withdrawn - ); - setHardtogetApplicants( - response.data.hardtoget - ); - setRejectedApplicants( - response.data.rejected - ); - setAcceptedApplicants( - response.data.accepted - ); + setRecruitmentApplicants(response.data.unprocessed); + setWithdrawnApplicants(response.data.withdrawn); + setHardtogetApplicants(response.data.hardtoget); + setRejectedApplicants(response.data.rejected); + setAcceptedApplicants(response.data.accepted); setShowSpinner(false); }) .catch((data) => { @@ -68,21 +62,11 @@ export function RecruitmentPositionOverviewPage() { positionId && updateRecruitmentApplicationStateForPosition(id, data) .then((response) => { - setRecruitmentApplicants( - response.data.unprocessed - ); - setWithdrawnApplicants( - response.data.withdrawn - ); - setHardtogetApplicants( - response.data.hardtoget - ); - setRejectedApplicants( - response.data.rejected - ); - setAcceptedApplicants( - response.data.accepted - ); + setRecruitmentApplicants(response.data.unprocessed); + setWithdrawnApplicants(response.data.withdrawn); + setHardtogetApplicants(response.data.hardtoget); + setRejectedApplicants(response.data.rejected); + setAcceptedApplicants(response.data.accepted); setShowSpinner(false); }) .catch((data) => { diff --git a/frontend/src/api.ts b/frontend/src/api.ts index dae569074..2e47cdff6 100644 --- a/frontend/src/api.ts +++ b/frontend/src/api.ts @@ -828,7 +828,7 @@ export async function getRecruitmentPositionOrganizedApplications( reverse({ pattern: ROUTES.backend.samfundet__recruitment_position_organized_applications, urlParams: { - pk: positionId + pk: positionId, }, }); return await axios.get(url, { withCredentials: true }); diff --git a/frontend/src/dto.ts b/frontend/src/dto.ts index 53d9da5e2..be99867cb 100644 --- a/frontend/src/dto.ts +++ b/frontend/src/dto.ts @@ -502,7 +502,7 @@ export type RecruitmentPositionOrganizedApplicationsDto = { rejected: RecruitmentApplicationDto[]; accepted: RecruitmentApplicationDto[]; hardtoget: RecruitmentApplicationDto[]; -} +}; export type RecruitmentApplicationDto = { id: string; From c4abc08dd1c7cf953d8936f57c8c0536ee3e50e3 Mon Sep 17 00:00:00 2001 From: magsyg Date: Tue, 12 Nov 2024 22:11:33 +0100 Subject: [PATCH 3/8] fixes --- backend/samfundet/serializers.py | 22 +++++++++++----------- backend/samfundet/views.py | 2 +- frontend/src/routes/backend.ts | 4 +--- 3 files changed, 13 insertions(+), 15 deletions(-) diff --git a/backend/samfundet/serializers.py b/backend/samfundet/serializers.py index ec2e05019..5f4e9b332 100644 --- a/backend/samfundet/serializers.py +++ b/backend/samfundet/serializers.py @@ -1096,7 +1096,7 @@ def get_application_count(self, application: RecruitmentApplication) -> int: class RecruitmentPositionOrganizedApplications(CustomBaseSerializer): - applicationSerializer = RecruitmentApplicationForGangSerializer + ApplicationSerializer = RecruitmentApplicationForGangSerializer unprocessed = serializers.SerializerMethodField(method_name='get_unprocessed', read_only=True) withdrawn = serializers.SerializerMethodField(method_name='get_withdrawn', read_only=True) accepted = serializers.SerializerMethodField(method_name='get_accepted', read_only=True) @@ -1107,27 +1107,27 @@ class Meta: model = RecruitmentPosition fields = ['unprocessed', 'withdrawn', 'accepted', 'rejected', 'hardtoget'] - def get_unprocessed(self, instance: RecruitmentPosition): + def get_unprocessed(self, instance: RecruitmentPosition): # noqa: ANN201 unprocessed = instance.applications.filter(withdrawn=False, recruiter_status=RecruitmentStatusChoices.NOT_SET) - return self.applicationSerializer(unprocessed, many=True).data + return self.ApplicationSerializer(unprocessed, many=True).data - def get_withdrawn(self, instance: RecruitmentPosition): + def get_withdrawn(self, instance: RecruitmentPosition): # noqa: ANN201 withdrawn = instance.applications.filter(withdrawn=True) - return self.applicationSerializer(withdrawn, many=True).data + return self.ApplicationSerializer(withdrawn, many=True).data - def get_rejected(self, instance: RecruitmentPosition): + def get_rejected(self, instance: RecruitmentPosition): # noqa: ANN201 rejected = instance.applications.filter( withdrawn=False, recruiter_status__in=[RecruitmentStatusChoices.AUTOMATIC_REJECTION, RecruitmentStatusChoices.REJECTION] ) - return self.applicationSerializer(rejected, many=True).data + return self.ApplicationSerializer(rejected, many=True).data - def get_accepted(self, instance: RecruitmentPosition): + def get_accepted(self, instance: RecruitmentPosition): # noqa: ANN201 accepted = instance.applications.filter(withdrawn=False, recruiter_status=RecruitmentStatusChoices.CALLED_AND_ACCEPTED) - return self.applicationSerializer(accepted, many=True).data + return self.ApplicationSerializer(accepted, many=True).data - def get_hardtoget(self, instance: RecruitmentPosition): + def get_hardtoget(self, instance: RecruitmentPosition): # noqa: ANN201 hardtoget = instance.applications.filter(withdrawn=False, recruiter_status=RecruitmentStatusChoices.CALLED_AND_REJECTED) - return self.applicationSerializer(hardtoget, many=True).data + return self.ApplicationSerializer(hardtoget, many=True).data class RecruitmentApplicationUpdateForGangSerializer(serializers.Serializer): diff --git a/backend/samfundet/views.py b/backend/samfundet/views.py index f9ae11a69..e77fdb5d5 100644 --- a/backend/samfundet/views.py +++ b/backend/samfundet/views.py @@ -42,7 +42,6 @@ from .homepage import homepage from .models.role import Role from .serializers import ( - RecruitmentPositionOrganizedApplications, TagSerializer, GangSerializer, MenuSerializer, @@ -88,6 +87,7 @@ RecruitmentSeparatePositionSerializer, RecruitmentApplicationForGangSerializer, RecruitmentUpdateUserPrioritySerializer, + RecruitmentPositionOrganizedApplications, RecruitmentPositionForApplicantSerializer, RecruitmentInterviewAvailabilitySerializer, RecruitmentApplicationForApplicantSerializer, diff --git a/frontend/src/routes/backend.ts b/frontend/src/routes/backend.ts index 5ca8ce229..c5b130e73 100644 --- a/frontend/src/routes/backend.ts +++ b/frontend/src/routes/backend.ts @@ -562,8 +562,6 @@ export const ROUTES_BACKEND = { samfundet__recruitment_applications_for_position_detail: '/api/recruitment-applications-for-position/:pk/', samfundet__interview_list: '/api/interview/', samfundet__interview_detail: '/api/interview/:pk/', - samfundet__api_root: '/api/', - samfundet__api_root: '/api/:format', samfundet__schema: '/schema/', samfundet__swagger_ui: '/schema/swagger-ui/', samfundet__redoc: '/schema/redoc/', @@ -610,4 +608,4 @@ export const ROUTES_BACKEND = { samfundet__purchase_feedback: '/purchase-feedback/', static__path: '/static/:path', media__path: '/media/:path', -} as const; \ No newline at end of file +} as const; From d2eb4cbef2bc9dbf6570b7c689e1f7413b614ddb Mon Sep 17 00:00:00 2001 From: magsyg Date: Fri, 6 Dec 2024 14:21:45 +0100 Subject: [PATCH 4/8] fixup urls --- backend/root/utils/routes.py | 2 -- backend/samfundet/urls.py | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/backend/root/utils/routes.py b/backend/root/utils/routes.py index 54672e72e..c9d4702b5 100644 --- a/backend/root/utils/routes.py +++ b/backend/root/utils/routes.py @@ -563,8 +563,6 @@ samfundet__recruitment_applications_for_position_detail = 'samfundet:recruitment_applications_for_position-detail' samfundet__interview_list = 'samfundet:interview-list' samfundet__interview_detail = 'samfundet:interview-detail' -samfundet__api_root = 'samfundet:api-root' -samfundet__api_root = 'samfundet:api-root' samfundet__schema = 'samfundet:schema' samfundet__swagger_ui = 'samfundet:swagger_ui' samfundet__redoc = 'samfundet:redoc' diff --git a/backend/samfundet/urls.py b/backend/samfundet/urls.py index 3bcda7a60..472fbb396 100644 --- a/backend/samfundet/urls.py +++ b/backend/samfundet/urls.py @@ -106,7 +106,7 @@ name='recruitment_application_update_state_gang', ), path( - 'recruitment-position-organized-applications//', + 'recruitment-position-organized-applications//', views.RecruitmentPositionOrganizedApplicationsView.as_view(), name='recruitment_position_organized_applications', ), From bbe23476c12b663e4fa1c6a9f042d30281c0dd60 Mon Sep 17 00:00:00 2001 From: magsyg Date: Fri, 6 Dec 2024 14:27:50 +0100 Subject: [PATCH 5/8] fix --- backend/samfundet/urls.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/samfundet/urls.py b/backend/samfundet/urls.py index e746ccf61..fc26a431d 100644 --- a/backend/samfundet/urls.py +++ b/backend/samfundet/urls.py @@ -106,7 +106,7 @@ name='recruitment_application_update_state_gang', ), path( - 'recruitment-position-organized-applications//', + 'recruitment-position-organized-applications//', views.RecruitmentPositionOrganizedApplicationsView.as_view(), name='recruitment_position_organized_applications', ), From e6a366a66d23aa935232fd3d25ca4fd876710097 Mon Sep 17 00:00:00 2001 From: magsyg Date: Fri, 6 Dec 2024 16:10:49 +0100 Subject: [PATCH 6/8] fixes --- backend/samfundet/serializers.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/backend/samfundet/serializers.py b/backend/samfundet/serializers.py index 6d16ac0f3..95f8b6c7f 100644 --- a/backend/samfundet/serializers.py +++ b/backend/samfundet/serializers.py @@ -1162,25 +1162,25 @@ class Meta: model = RecruitmentPosition fields = ['unprocessed', 'withdrawn', 'accepted', 'rejected', 'hardtoget'] - def get_unprocessed(self, instance: RecruitmentPosition): # noqa: ANN201 + def get_unprocessed(self, instance: RecruitmentPosition): # noqa: ANN201 type: ignore[no-untyped-def] unprocessed = instance.applications.filter(withdrawn=False, recruiter_status=RecruitmentStatusChoices.NOT_SET) return self.ApplicationSerializer(unprocessed, many=True).data - def get_withdrawn(self, instance: RecruitmentPosition): # noqa: ANN201 + def get_withdrawn(self, instance: RecruitmentPosition): # noqa: ANN201 type: ignore[no-untyped-def] withdrawn = instance.applications.filter(withdrawn=True) return self.ApplicationSerializer(withdrawn, many=True).data - def get_rejected(self, instance: RecruitmentPosition): # noqa: ANN201 + def get_rejected(self, instance: RecruitmentPosition): # noqa: ANN201 type: ignore[no-untyped-def] rejected = instance.applications.filter( withdrawn=False, recruiter_status__in=[RecruitmentStatusChoices.AUTOMATIC_REJECTION, RecruitmentStatusChoices.REJECTION] ) return self.ApplicationSerializer(rejected, many=True).data - def get_accepted(self, instance: RecruitmentPosition): # noqa: ANN201 + def get_accepted(self, instance: RecruitmentPosition): # noqa: ANN201 type: ignore[no-untyped-def] accepted = instance.applications.filter(withdrawn=False, recruiter_status=RecruitmentStatusChoices.CALLED_AND_ACCEPTED) return self.ApplicationSerializer(accepted, many=True).data - def get_hardtoget(self, instance: RecruitmentPosition): # noqa: ANN201 + def get_hardtoget(self, instance: RecruitmentPosition): # noqa: ANN201 type: ignore[no-untyped-def] hardtoget = instance.applications.filter(withdrawn=False, recruiter_status=RecruitmentStatusChoices.CALLED_AND_REJECTED) return self.ApplicationSerializer(hardtoget, many=True).data From 7cef1d6f0e690d062055255956a3216118e6996c Mon Sep 17 00:00:00 2001 From: magsyg Date: Fri, 6 Dec 2024 16:25:36 +0100 Subject: [PATCH 7/8] add return type --- backend/samfundet/serializers.py | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/backend/samfundet/serializers.py b/backend/samfundet/serializers.py index 95f8b6c7f..3d3cad9dc 100644 --- a/backend/samfundet/serializers.py +++ b/backend/samfundet/serializers.py @@ -76,6 +76,8 @@ if TYPE_CHECKING: from typing import Any +from rest_framework.utils.serializer_helpers import ReturnList + class TagSerializer(CustomBaseSerializer): class Meta: @@ -1162,25 +1164,25 @@ class Meta: model = RecruitmentPosition fields = ['unprocessed', 'withdrawn', 'accepted', 'rejected', 'hardtoget'] - def get_unprocessed(self, instance: RecruitmentPosition): # noqa: ANN201 type: ignore[no-untyped-def] + def get_unprocessed(self, instance: RecruitmentPosition) -> ReturnList: unprocessed = instance.applications.filter(withdrawn=False, recruiter_status=RecruitmentStatusChoices.NOT_SET) return self.ApplicationSerializer(unprocessed, many=True).data - def get_withdrawn(self, instance: RecruitmentPosition): # noqa: ANN201 type: ignore[no-untyped-def] + def get_withdrawn(self, instance: RecruitmentPosition) -> ReturnList: withdrawn = instance.applications.filter(withdrawn=True) return self.ApplicationSerializer(withdrawn, many=True).data - def get_rejected(self, instance: RecruitmentPosition): # noqa: ANN201 type: ignore[no-untyped-def] + def get_rejected(self, instance: RecruitmentPosition) -> ReturnList: rejected = instance.applications.filter( withdrawn=False, recruiter_status__in=[RecruitmentStatusChoices.AUTOMATIC_REJECTION, RecruitmentStatusChoices.REJECTION] ) return self.ApplicationSerializer(rejected, many=True).data - def get_accepted(self, instance: RecruitmentPosition): # noqa: ANN201 type: ignore[no-untyped-def] + def get_accepted(self, instance: RecruitmentPosition) -> ReturnList: accepted = instance.applications.filter(withdrawn=False, recruiter_status=RecruitmentStatusChoices.CALLED_AND_ACCEPTED) return self.ApplicationSerializer(accepted, many=True).data - def get_hardtoget(self, instance: RecruitmentPosition): # noqa: ANN201 type: ignore[no-untyped-def] + def get_hardtoget(self, instance: RecruitmentPosition) -> ReturnList: hardtoget = instance.applications.filter(withdrawn=False, recruiter_status=RecruitmentStatusChoices.CALLED_AND_REJECTED) return self.ApplicationSerializer(hardtoget, many=True).data From 2fc06bd82681a41b81e33ddaa216e85ded32c586 Mon Sep 17 00:00:00 2001 From: magsyg Date: Mon, 23 Dec 2024 14:48:05 +0100 Subject: [PATCH 8/8] fix biome --- .../RecruitmentPositionOverviewPage.tsx | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/frontend/src/PagesAdmin/RecruitmentPositionOverviewPage/RecruitmentPositionOverviewPage.tsx b/frontend/src/PagesAdmin/RecruitmentPositionOverviewPage/RecruitmentPositionOverviewPage.tsx index 3f37b74e4..eeb523686 100644 --- a/frontend/src/PagesAdmin/RecruitmentPositionOverviewPage/RecruitmentPositionOverviewPage.tsx +++ b/frontend/src/PagesAdmin/RecruitmentPositionOverviewPage/RecruitmentPositionOverviewPage.tsx @@ -4,11 +4,7 @@ import { useNavigate, useParams } from 'react-router-dom'; import { toast } from 'react-toastify'; import { Button, RecruitmentApplicantsStatus } from '~/Components'; import { Text } from '~/Components/Text/Text'; -import { - getRecruitmentApplicationsForGang, - getRecruitmentPositionOrganizedApplications, - updateRecruitmentApplicationStateForPosition, -} from '~/api'; +import { getRecruitmentPositionOrganizedApplications, updateRecruitmentApplicationStateForPosition } from '~/api'; import type { RecruitmentApplicationDto, RecruitmentApplicationStateDto } from '~/dto'; import { useTitle } from '~/hooks'; import { STATUS } from '~/http_status_codes';