From f28357b95f11529727309647d2d1ce0aa2c499ce Mon Sep 17 00:00:00 2001 From: magsyg Date: Sun, 8 Dec 2024 15:47:33 +0100 Subject: [PATCH 1/6] fix postitions can have gangs from seperate organizations --- .../seed_scripts/recruitment_position.py | 2 +- backend/samfundet/conftest.py | 26 ++++++++++---- backend/samfundet/models/recruitment.py | 17 +++++++-- .../models/tests/test_recruitment.py | 36 +++++++++++++++++++ backend/samfundet/tests/test_roles.py | 8 ++--- 5 files changed, 75 insertions(+), 14 deletions(-) diff --git a/backend/root/management/commands/seed_scripts/recruitment_position.py b/backend/root/management/commands/seed_scripts/recruitment_position.py index 0a2739d9f..5d6198dff 100644 --- a/backend/root/management/commands/seed_scripts/recruitment_position.py +++ b/backend/root/management/commands/seed_scripts/recruitment_position.py @@ -21,10 +21,10 @@ def seed(): RecruitmentPosition.objects.all().delete() yield 0, 'Deleted old recruitmentpositions' - gangs = Gang.objects.all() recruitments = Recruitment.objects.all() created_count = 0 for recruitment_index, recruitment in enumerate(recruitments): + gangs = Gang.objects.filter(organization=recruitment.organization) for gang_index, gang in enumerate(sample(list(gangs), 6)): for i in range(2): # Create 2 instances for each gang and recruitment position_data = POSITION_DATA.copy() diff --git a/backend/samfundet/conftest.py b/backend/samfundet/conftest.py index 8efc8ff6e..5b37ad608 100644 --- a/backend/samfundet/conftest.py +++ b/backend/samfundet/conftest.py @@ -237,26 +237,38 @@ def fixture_organization2() -> Iterator[Organization]: @pytest.fixture def fixture_gang(fixture_organization: Organization) -> Iterator[Gang]: - organization = Gang.objects.create( + gang = Gang.objects.create( name_nb='Gang', name_en='Gang', abbreviation='G', organization=fixture_organization, ) - yield organization - organization.delete() + yield gang + gang.delete() @pytest.fixture -def fixture_gang2(fixture_organization2: Organization) -> Iterator[Gang]: - organization = Gang.objects.create( +def fixture_gang2(fixture_organization: Organization) -> Iterator[Gang]: + gang = Gang.objects.create( name_nb='Gang 2', name_en='Gang 2', abbreviation='G2', + organization=fixture_organization, + ) + yield gang + gang.delete() + + +@pytest.fixture +def fixture_gang_org2(fixture_organization2: Organization) -> Iterator[Gang]: + gang = Gang.objects.create( + name_nb='Gang 3', + name_en='Gang 3', + abbreviation='G3', organization=fixture_organization2, ) - yield organization - organization.delete() + yield gang + gang.delete() @pytest.fixture diff --git a/backend/samfundet/models/recruitment.py b/backend/samfundet/models/recruitment.py index 514fcda9d..234dc5df2 100644 --- a/backend/samfundet/models/recruitment.py +++ b/backend/samfundet/models/recruitment.py @@ -185,11 +185,24 @@ def resolve_org(self, *, return_id: bool = False) -> Organization | int: def __str__(self) -> str: return f'Position: {self.name_en} in {self.recruitment}' + # Error messages + ONLY_ONE_OWNER_ERROR = 'Position must be owned by either gang or section, not both' + NO_OWNER_ERROR = 'Position must have an owner, either a gang or a gang section' + POSITION_NOT_IN_RECRUITMENTORGANIZATION_ERROR = 'Position must be of the organization which hosts the recruitment' + def clean(self) -> None: super().clean() + errors: dict[str, list[ValidationError]] = defaultdict(list) - if (self.gang and self.section) or not (self.gang or self.section): - raise ValidationError('Position must be owned by either gang or section, not both') + if self.gang and self.gang.organization != self.recruitment.organization: + errors['gang'].append(self.POSITION_NOT_IN_RECRUITMENTORGANIZATION_ERROR) + if self.gang and self.section: + errors['gang'].append(self.ONLY_ONE_OWNER_ERROR) + errors['section'].append(self.ONLY_ONE_OWNER_ERROR) + elif not (self.gang or self.section): + errors['gang'].append(self.NO_OWNER_ERROR) + errors['section'].append(self.NO_OWNER_ERROR) + raise ValidationError(errors) def save(self, *args: tuple, **kwargs: dict) -> None: if self.norwegian_applicants_only: diff --git a/backend/samfundet/models/tests/test_recruitment.py b/backend/samfundet/models/tests/test_recruitment.py index 5a754d239..0ec22b77d 100644 --- a/backend/samfundet/models/tests/test_recruitment.py +++ b/backend/samfundet/models/tests/test_recruitment.py @@ -95,6 +95,42 @@ def test_actual_deadline_before_shown_deadline(self, fixture_org): assert Recruitment.SHOWN_AFTER_ACTUAL_ERROR in e['shown_application_deadline'] +class TestRecruitmentPosition: + default_data = { + 'name_en': 'Name_en', + 'name_nb': 'Name_nb', + 'short_description_nb': 'short_description_nb', + 'short_description_en': 'short_description_en', + 'long_description_nb': 'long_description_nb', + 'long_description_en': 'long_description_en', + 'is_funksjonaer_position': False, + 'default_application_letter_nb': 'default_application_letter_nb', + 'default_application_letter_en': 'default_application_letter_en', + 'norwegian_applicants_only': False, + 'tags': 'tag1, tag2, tag3', + } + + def test_create_recruitmentposition_gang(self, fixture_recruitment: Recruitment, fixture_gang: Gang): + test_position = RecruitmentPosition.objects.create(**self.default_data, recruitment=fixture_recruitment, gang=fixture_gang) + assert test_position.id + + def test_edit_recruitmentposition_gang_from_other_org(self, fixture_recruitment: Recruitment, fixture_gang: Gang, fixture_gang_org2: Gang): + test_position = RecruitmentPosition.objects.create(**self.default_data, recruitment=fixture_recruitment, gang=fixture_gang) + assert test_position.id + + with pytest.raises(ValidationError) as error: + test_position.gang = fixture_gang_org2 + test_position.save() + e = dict(error.value) + assert RecruitmentPosition.POSITION_NOT_IN_RECRUITMENTORGANIZATION_ERROR in e['gang'] + + def test_create_recruitmentposition_gang_from_other_org(self, fixture_recruitment: Recruitment, fixture_gang_org2: Gang): + with pytest.raises(ValidationError) as error: + RecruitmentPosition.objects.create(**self.default_data, recruitment=fixture_recruitment, gang=fixture_gang_org2) + e = dict(error.value) + assert RecruitmentPosition.POSITION_NOT_IN_RECRUITMENTORGANIZATION_ERROR in e['gang'] + + class TestRecruitmentStats: def test_recruitment_has_stats(self, fixture_recruitment: Recruitment): """Check if fixture_recruitment has the related object""" diff --git a/backend/samfundet/tests/test_roles.py b/backend/samfundet/tests/test_roles.py index 859ecee98..61e1da489 100644 --- a/backend/samfundet/tests/test_roles.py +++ b/backend/samfundet/tests/test_roles.py @@ -119,7 +119,7 @@ def test_has_perm_different_orgs( def test_has_perm_different_gangs( fixture_user: User, fixture_gang: Gang, - fixture_gang2: Gang, + fixture_gang_org2: Gang, fixture_gang_permission: Permission, fixture_role: Role, ): @@ -132,7 +132,7 @@ def test_has_perm_different_gangs( UserGangRole.objects.create(user=fixture_user, role=fixture_role, obj=fixture_gang) assert backend.has_perm(fixture_user, fixture_gang_permission.codename, fixture_gang) - assert not backend.has_perm(fixture_user, fixture_gang_permission.codename, fixture_gang2) + assert not backend.has_perm(fixture_user, fixture_gang_permission.codename, fixture_gang_org2) def test_has_perm_different_gang_sections( @@ -185,7 +185,7 @@ def test_has_perm_org_downward( fixture_organization: Organization, fixture_organization2: Organization, fixture_gang: Gang, - fixture_gang2: Gang, + fixture_gang_org2: Gang, fixture_gang_section: GangSection, fixture_role: Role, fixture_org_permission: Permission, @@ -230,7 +230,7 @@ def test_has_perm_org_downward( assert backend.has_perm(fixture_user, fixture_gang_section_permission.codename, fixture_gang_section) - fixture_gang_section.gang = fixture_gang2 + fixture_gang_section.gang = fixture_gang_org2 assert not backend.has_perm(fixture_user, fixture_gang_section_permission.codename, fixture_gang_section) From 54baf1af775db868c220154b13ebdcb4c53d6ad4 Mon Sep 17 00:00:00 2001 From: magsyg Date: Wed, 11 Dec 2024 12:53:18 +0100 Subject: [PATCH 2/6] fixup gang position to use loader --- backend/samfundet/urls.py | 2 +- backend/samfundet/views.py | 22 ++++---- .../RecruitmentGangAdminPage.tsx | 53 +++++++++++-------- frontend/src/api.ts | 2 +- frontend/src/router/loaders.ts | 5 ++ frontend/src/router/router.tsx | 1 + frontend/src/routes/backend.ts | 5 +- 7 files changed, 51 insertions(+), 39 deletions(-) diff --git a/backend/samfundet/urls.py b/backend/samfundet/urls.py index 940ac346f..63ebf87e5 100644 --- a/backend/samfundet/urls.py +++ b/backend/samfundet/urls.py @@ -94,7 +94,7 @@ views.RecruitmentInterviewGroupView.as_view(), name='recruitment_shared_interviews', ), - path('recruitment-positions-gang-for-gangs/', views.RecruitmentPositionsPerGangForGangView.as_view(), name='recruitment_positions_gang_for_gangs'), + path('recruitment-positions-gang-for-gangs///', views.RecruitmentPositionsPerGangForGangView.as_view(), name='recruitment_positions_gang_for_gangs'), path('recruitment-set-interview//', views.RecruitmentApplicationSetInterviewView.as_view(), name='recruitment_set_interview'), path( 'recruitment-application-states-choices', diff --git a/backend/samfundet/views.py b/backend/samfundet/views.py index 59666f8aa..c70acc721 100644 --- a/backend/samfundet/views.py +++ b/backend/samfundet/views.py @@ -731,7 +731,7 @@ def get_queryset(self) -> Response | None: @method_decorator(ensure_csrf_cookie, 'dispatch') -class RecruitmentPositionsPerGangForApplicantView(ListAPIView): +class RecruitmentPositionsPerGangForApplicantView(APIView): permission_classes = [AllowAny] serializer_class = RecruitmentPositionForApplicantSerializer @@ -748,20 +748,18 @@ def get_queryset(self) -> Response | None: @method_decorator(ensure_csrf_cookie, 'dispatch') -class RecruitmentPositionsPerGangForGangView(ListAPIView): +class RecruitmentPositionsPerGangForGangView(APIView): permission_classes = [IsAuthenticated] serializer_class = RecruitmentPositionSerializer - def get_queryset(self) -> Response | None: - """ - Optionally restricts the returned positions to a given recruitment, - by filtering against a `recruitment` query parameter in the URL. - """ - recruitment = self.request.query_params.get('recruitment', None) - gang = self.request.query_params.get('gang', None) - if recruitment is not None and gang is not None: - return RecruitmentPosition.objects.filter(gang=gang, recruitment=recruitment) - return None + def get(self, request: Request, recruitment_id: int, gang_id: int) -> Response: + gang = get_object_or_404(Gang, id=gang_id) + recruitment = get_object_or_404(Recruitment, id=recruitment_id) + if recruitment.resolve_org() != gang.resolve_org(): + return Response("Gang not found in recruitment organization", status=status.HTTP_404_NOT_FOUND) + data = RecruitmentPosition.objects.filter(gang=gang, recruitment=recruitment) + return Response(data=self.serializer_class(data,many=True).data, status=status.HTTP_200_OK) + class SendRejectionMailView(APIView): diff --git a/frontend/src/PagesAdmin/RecruitmentGangAdminPage/RecruitmentGangAdminPage.tsx b/frontend/src/PagesAdmin/RecruitmentGangAdminPage/RecruitmentGangAdminPage.tsx index 936037ebd..a293049fa 100644 --- a/frontend/src/PagesAdmin/RecruitmentGangAdminPage/RecruitmentGangAdminPage.tsx +++ b/frontend/src/PagesAdmin/RecruitmentGangAdminPage/RecruitmentGangAdminPage.tsx @@ -1,10 +1,10 @@ import { useEffect, useState } from 'react'; import { useTranslation } from 'react-i18next'; -import { useNavigate, useParams } from 'react-router-dom'; +import { useLoaderData, useNavigate, useParams, useRouteLoaderData } from 'react-router-dom'; import { toast } from 'react-toastify'; import { Button, CrudButtons, Link } from '~/Components'; import { Table } from '~/Components/Table'; -import { getGang, getRecruitment, getRecruitmentPositionsGangForGang } from '~/api'; +import { getRecruitmentPositionsGangForGang } from '~/api'; import type { GangDto, RecruitmentDto, RecruitmentPositionDto } from '~/dto'; import { useTitle } from '~/hooks'; import { STATUS } from '~/http_status_codes'; @@ -14,11 +14,13 @@ import { ROUTES } from '~/routes'; import { dbT, getObjectFieldOrNumber, lowerCapitalize } from '~/utils'; import { AdminPageLayout } from '../AdminPageLayout/AdminPageLayout'; import styles from './RecruitmentGangAdminPage.module.scss'; +import { RecruitmentGangLoader } from '~/router/loaders'; export function RecruitmentGangAdminPage() { const { recruitmentId, gangId } = useParams(); const navigate = useNavigate(); const [gang, setGang] = useState(); + const loader = useLoaderData() as RecruitmentGangLoader | undefined; const [recruitment, setRecruitment] = useState(); const [recruitmentPositions, setRecruitmentPositions] = useState([]); const [showSpinner, setShowSpinner] = useState(true); @@ -32,29 +34,36 @@ export function RecruitmentGangAdminPage() { // biome-ignore lint/correctness/useExhaustiveDependencies: t and navigate do not need to be in deplist useEffect(() => { if (recruitmentId && gangId) { - Promise.allSettled([ - getRecruitmentPositionsGangForGang(recruitmentId, gangId).then((data) => { - setRecruitmentPositions(data.data); - }), - getGang(gangId).then((data) => { - setGang(data); - }), - getRecruitment(recruitmentId).then(async (data) => { - setRecruitment(data.data); - }), - ]) - .then(() => { - setShowSpinner(false); - }) - .catch((data) => { - if (data.request.status === STATUS.HTTP_404_NOT_FOUND) { - navigate(ROUTES.frontend.not_found, { replace: true }); - } - toast.error(t(KEY.common_something_went_wrong)); - }); + getRecruitmentPositionsGangForGang(recruitmentId, gangId).then((data) => { + setRecruitmentPositions(data.data); + }) + .catch((data) => { + if (data.request.status === STATUS.HTTP_404_NOT_FOUND) { + navigate(ROUTES.frontend.not_found, { replace: true }); + } + toast.error(t(KEY.common_something_went_wrong)); + }) } }, [recruitmentId, gangId]); + + useEffect(()=> { + if(recruitmentPositions && gang && gang) { + setShowSpinner(false); + } + }, + [recruitmentPositions, gang, recruitment] + ) + + useEffect(() => { + if (loader) { + setGang(loader.gang); + setRecruitment(loader.recruitment); + } + }, [loader]); + + + const tableColumns = [ { content: t(KEY.recruitment_position), sortable: true }, { content: t(KEY.recruitment_jobtype), sortable: true }, diff --git a/frontend/src/api.ts b/frontend/src/api.ts index e77eb2fb9..2300114c3 100644 --- a/frontend/src/api.ts +++ b/frontend/src/api.ts @@ -597,7 +597,7 @@ export async function getRecruitmentPositionsGangForGang( BACKEND_DOMAIN + reverse({ pattern: ROUTES.backend.samfundet__recruitment_positions_gang_for_gangs, - queryParams: { recruitment: recruitmentId, gang: gangId }, + urlParams: { recruitmentId: recruitmentId, gangId: gangId }, }); const response = await axios.get(url, { withCredentials: true }); diff --git a/frontend/src/router/loaders.ts b/frontend/src/router/loaders.ts index c3c1ec630..1e373201e 100644 --- a/frontend/src/router/loaders.ts +++ b/frontend/src/router/loaders.ts @@ -14,6 +14,11 @@ export type PositionLoader = { position: RecruitmentPositionDto | undefined; }; +export type RecruitmentGangLoader = { + recruitment: RecruitmentDto | undefined; + gang: GangDto | undefined; +}; + export type SeparatePositionLoader = { separatePosition: RecruitmentSeparatePositionDto | undefined; }; diff --git a/frontend/src/router/router.tsx b/frontend/src/router/router.tsx index fd29dc9e0..bc3dc9d28 100644 --- a/frontend/src/router/router.tsx +++ b/frontend/src/router/router.tsx @@ -566,6 +566,7 @@ export const router = createBrowserRouter( > } />} /> Date: Wed, 11 Dec 2024 12:53:47 +0100 Subject: [PATCH 3/6] formating --- backend/samfundet/urls.py | 6 +++- backend/samfundet/views.py | 5 ++- .../RecruitmentGangAdminPage.tsx | 32 ++++++++----------- 3 files changed, 21 insertions(+), 22 deletions(-) diff --git a/backend/samfundet/urls.py b/backend/samfundet/urls.py index 63ebf87e5..1b183eab5 100644 --- a/backend/samfundet/urls.py +++ b/backend/samfundet/urls.py @@ -94,7 +94,11 @@ views.RecruitmentInterviewGroupView.as_view(), name='recruitment_shared_interviews', ), - path('recruitment-positions-gang-for-gangs///', views.RecruitmentPositionsPerGangForGangView.as_view(), name='recruitment_positions_gang_for_gangs'), + path( + 'recruitment-positions-gang-for-gangs///', + views.RecruitmentPositionsPerGangForGangView.as_view(), + name='recruitment_positions_gang_for_gangs', + ), path('recruitment-set-interview//', views.RecruitmentApplicationSetInterviewView.as_view(), name='recruitment_set_interview'), path( 'recruitment-application-states-choices', diff --git a/backend/samfundet/views.py b/backend/samfundet/views.py index c70acc721..4ed427c79 100644 --- a/backend/samfundet/views.py +++ b/backend/samfundet/views.py @@ -756,10 +756,9 @@ def get(self, request: Request, recruitment_id: int, gang_id: int) -> Response: gang = get_object_or_404(Gang, id=gang_id) recruitment = get_object_or_404(Recruitment, id=recruitment_id) if recruitment.resolve_org() != gang.resolve_org(): - return Response("Gang not found in recruitment organization", status=status.HTTP_404_NOT_FOUND) + return Response('Gang not found in recruitment organization', status=status.HTTP_404_NOT_FOUND) data = RecruitmentPosition.objects.filter(gang=gang, recruitment=recruitment) - return Response(data=self.serializer_class(data,many=True).data, status=status.HTTP_200_OK) - + return Response(data=self.serializer_class(data, many=True).data, status=status.HTTP_200_OK) class SendRejectionMailView(APIView): diff --git a/frontend/src/PagesAdmin/RecruitmentGangAdminPage/RecruitmentGangAdminPage.tsx b/frontend/src/PagesAdmin/RecruitmentGangAdminPage/RecruitmentGangAdminPage.tsx index a293049fa..df8a4b86e 100644 --- a/frontend/src/PagesAdmin/RecruitmentGangAdminPage/RecruitmentGangAdminPage.tsx +++ b/frontend/src/PagesAdmin/RecruitmentGangAdminPage/RecruitmentGangAdminPage.tsx @@ -10,11 +10,11 @@ import { useTitle } from '~/hooks'; import { STATUS } from '~/http_status_codes'; import { KEY } from '~/i18n/constants'; import { reverse } from '~/named-urls'; +import type { RecruitmentGangLoader } from '~/router/loaders'; import { ROUTES } from '~/routes'; import { dbT, getObjectFieldOrNumber, lowerCapitalize } from '~/utils'; import { AdminPageLayout } from '../AdminPageLayout/AdminPageLayout'; import styles from './RecruitmentGangAdminPage.module.scss'; -import { RecruitmentGangLoader } from '~/router/loaders'; export function RecruitmentGangAdminPage() { const { recruitmentId, gangId } = useParams(); @@ -34,26 +34,24 @@ export function RecruitmentGangAdminPage() { // biome-ignore lint/correctness/useExhaustiveDependencies: t and navigate do not need to be in deplist useEffect(() => { if (recruitmentId && gangId) { - getRecruitmentPositionsGangForGang(recruitmentId, gangId).then((data) => { - setRecruitmentPositions(data.data); - }) - .catch((data) => { - if (data.request.status === STATUS.HTTP_404_NOT_FOUND) { - navigate(ROUTES.frontend.not_found, { replace: true }); - } - toast.error(t(KEY.common_something_went_wrong)); - }) + getRecruitmentPositionsGangForGang(recruitmentId, gangId) + .then((data) => { + setRecruitmentPositions(data.data); + }) + .catch((data) => { + if (data.request.status === STATUS.HTTP_404_NOT_FOUND) { + navigate(ROUTES.frontend.not_found, { replace: true }); + } + toast.error(t(KEY.common_something_went_wrong)); + }); } }, [recruitmentId, gangId]); - - useEffect(()=> { - if(recruitmentPositions && gang && gang) { + useEffect(() => { + if (recruitmentPositions && gang && gang) { setShowSpinner(false); } - }, - [recruitmentPositions, gang, recruitment] - ) + }, [recruitmentPositions, gang, recruitment]); useEffect(() => { if (loader) { @@ -62,8 +60,6 @@ export function RecruitmentGangAdminPage() { } }, [loader]); - - const tableColumns = [ { content: t(KEY.recruitment_position), sortable: true }, { content: t(KEY.recruitment_jobtype), sortable: true }, From c26dd359495838c952108af914f629e885ad0ba9 Mon Sep 17 00:00:00 2001 From: magsyg Date: Wed, 11 Dec 2024 12:55:59 +0100 Subject: [PATCH 4/6] fix --- .../RecruitmentGangAdminPage/RecruitmentGangAdminPage.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/PagesAdmin/RecruitmentGangAdminPage/RecruitmentGangAdminPage.tsx b/frontend/src/PagesAdmin/RecruitmentGangAdminPage/RecruitmentGangAdminPage.tsx index df8a4b86e..5c9ef2814 100644 --- a/frontend/src/PagesAdmin/RecruitmentGangAdminPage/RecruitmentGangAdminPage.tsx +++ b/frontend/src/PagesAdmin/RecruitmentGangAdminPage/RecruitmentGangAdminPage.tsx @@ -48,7 +48,7 @@ export function RecruitmentGangAdminPage() { }, [recruitmentId, gangId]); useEffect(() => { - if (recruitmentPositions && gang && gang) { + if (recruitmentPositions && gang && recruitment) { setShowSpinner(false); } }, [recruitmentPositions, gang, recruitment]); From bf5141bd9992835d4b5bc978a53b41735f255243 Mon Sep 17 00:00:00 2001 From: magsyg Date: Fri, 20 Dec 2024 17:15:23 +0100 Subject: [PATCH 5/6] fix merge --- backend/samfundet/models/tests/test_recruitment.py | 3 ++- .../RecruitmentGangAdminPage/RecruitmentGangAdminPage.tsx | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/backend/samfundet/models/tests/test_recruitment.py b/backend/samfundet/models/tests/test_recruitment.py index 49ec187a2..76c81b08a 100644 --- a/backend/samfundet/models/tests/test_recruitment.py +++ b/backend/samfundet/models/tests/test_recruitment.py @@ -109,7 +109,7 @@ class TestRecruitmentPosition: 'norwegian_applicants_only': False, 'tags': 'tag1, tag2, tag3', } - + def test_create_recruitmentposition_gang(self, fixture_recruitment: Recruitment, fixture_gang: Gang): test_position = RecruitmentPosition.objects.create(**self.default_data, recruitment=fixture_recruitment, gang=fixture_gang) assert test_position.id @@ -171,6 +171,7 @@ def test_create_recruitmentposition_file_upload(self, fixture_gang_section: Gang ) assert test_position.id + class TestRecruitmentStats: def test_recruitment_has_stats(self, fixture_recruitment: Recruitment): """Check if fixture_recruitment has the related object""" diff --git a/frontend/src/PagesAdmin/RecruitmentGangAdminPage/RecruitmentGangAdminPage.tsx b/frontend/src/PagesAdmin/RecruitmentGangAdminPage/RecruitmentGangAdminPage.tsx index 5c9ef2814..51526ef44 100644 --- a/frontend/src/PagesAdmin/RecruitmentGangAdminPage/RecruitmentGangAdminPage.tsx +++ b/frontend/src/PagesAdmin/RecruitmentGangAdminPage/RecruitmentGangAdminPage.tsx @@ -1,6 +1,6 @@ import { useEffect, useState } from 'react'; import { useTranslation } from 'react-i18next'; -import { useLoaderData, useNavigate, useParams, useRouteLoaderData } from 'react-router-dom'; +import { useLoaderData, useNavigate, useParams } from 'react-router-dom'; import { toast } from 'react-toastify'; import { Button, CrudButtons, Link } from '~/Components'; import { Table } from '~/Components/Table'; From 31ff44f7dc3c291ca9efde3746738fe123fea55b Mon Sep 17 00:00:00 2001 From: magsyg Date: Mon, 23 Dec 2024 14:58:59 +0100 Subject: [PATCH 6/6] fixup merge --- backend/samfundet/models/tests/test_recruitment.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/backend/samfundet/models/tests/test_recruitment.py b/backend/samfundet/models/tests/test_recruitment.py index 76c81b08a..e25d807d4 100644 --- a/backend/samfundet/models/tests/test_recruitment.py +++ b/backend/samfundet/models/tests/test_recruitment.py @@ -141,9 +141,9 @@ def test_create_recruitmentposition_no_section(self): assert RecruitmentPosition.NO_OWNER_ERROR in e['section'] assert RecruitmentPosition.NO_OWNER_ERROR in e['gang'] - def test_create_recruitmentposition_only_one_owner(self, fixture_gang_section: GangSection, fixture_gang: Gang): + def test_create_recruitmentposition_only_one_owner(self, fixture_recruitment: Recruitment, fixture_gang_section: GangSection, fixture_gang: Gang): with pytest.raises(ValidationError) as error: - RecruitmentPosition.objects.create(**self.default_data, section=fixture_gang_section, gang=fixture_gang) + RecruitmentPosition.objects.create(**self.default_data, recruitment=fixture_recruitment, section=fixture_gang_section, gang=fixture_gang) e = dict(error.value) assert RecruitmentPosition.ONLY_ONE_OWNER_ERROR in e['section'] assert RecruitmentPosition.ONLY_ONE_OWNER_ERROR in e['gang']