Skip to content

Commit 3612405

Browse files
♻️(ingestion-presentation) move files related to archive offer (#532)
* ♻️(ingestion-presentation) move files related to archive offer * ♻️(ingestion-presentation) move archive usecase API to ingestion * ♻️(ingestion) remove unuseful auth declaration
1 parent 1769366 commit 3612405

9 files changed

Lines changed: 84 additions & 83 deletions

File tree

src/ingestion/application/use_cases/archive_offer.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ def __init__(
1313
self._web_api_key = web_api_key
1414

1515
async def execute(self, reference: str) -> None:
16-
url = f"{self._web_base_url}/api/offers/{reference}/archive"
16+
url = f"{self._web_base_url}/api/data/offers/{reference}/archive"
1717
response = await self._client.post(
1818
url,
1919
headers={"Authorization": f"Api-Key {self._web_api_key}"},

src/ingestion/tests/integration/test_webhook_archive.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ async def test_vacancy_status_archived_calls_archive(
2020
):
2121
httpx_mock.add_response(
2222
method="POST",
23-
url=f"{WEB_BASE_URL}/api/offers/{REFERENCE}/archive",
23+
url=f"{WEB_BASE_URL}/api/data/offers/{REFERENCE}/archive",
2424
status_code=200,
2525
)
2626
payload = {
@@ -40,7 +40,7 @@ async def test_vacancy_status_archived_calls_archive(
4040
async def test_vacancy_deleted_calls_archive(talentsoft_client, httpx_mock: HTTPXMock):
4141
httpx_mock.add_response(
4242
method="POST",
43-
url=f"{WEB_BASE_URL}/api/offers/{REFERENCE}/archive",
43+
url=f"{WEB_BASE_URL}/api/data/offers/{REFERENCE}/archive",
4444
status_code=200,
4545
)
4646
payload = {"event_type": "vacancy_deleted", "reference": REFERENCE}

src/ingestion/tests/unit/test_archive_offer_use_case.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,15 +24,15 @@ async def test_execute_posts_to_archive_endpoint(
2424
):
2525
httpx_mock.add_response(
2626
method="POST",
27-
url=f"{WEB_BASE_URL}/api/offers/{REFERENCE}/archive",
27+
url=f"{WEB_BASE_URL}/api/data/offers/{REFERENCE}/archive",
2828
status_code=200,
2929
)
3030
await use_case.execute(REFERENCE)
3131

3232
requests = httpx_mock.get_requests()
3333
assert len(requests) == 1
3434
assert requests[0].url == httpx.URL(
35-
f"{WEB_BASE_URL}/api/offers/{REFERENCE}/archive"
35+
f"{WEB_BASE_URL}/api/data/offers/{REFERENCE}/archive"
3636
)
3737
assert requests[0].headers["authorization"] == f"Api-Key {WEB_API_KEY}"
3838

@@ -43,7 +43,7 @@ async def test_execute_raises_on_error_response(
4343
):
4444
httpx_mock.add_response(
4545
method="POST",
46-
url=f"{WEB_BASE_URL}/api/offers/{REFERENCE}/archive",
46+
url=f"{WEB_BASE_URL}/api/data/offers/{REFERENCE}/archive",
4747
status_code=500,
4848
)
4949
with pytest.raises(httpx.HTTPStatusError):

src/web/presentation/api/urls.py

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
TokenRefreshView,
55
)
66

7-
from presentation.api.views import ArchiveOffersView, HueyHealthView, RedocView
7+
from presentation.api.views import HueyHealthView, RedocView
88

99
app_name = "api"
1010

@@ -13,9 +13,4 @@
1313
path("token/refresh/", TokenRefreshView.as_view(), name="token_refresh"),
1414
path("health/huey/", HueyHealthView.as_view(), name="health_huey"),
1515
path("schema/redoc/", RedocView.as_view(), name="redoc"),
16-
path(
17-
"offers/<str:reference>/archive/",
18-
ArchiveOffersView.as_view(),
19-
name="offers_archive",
20-
),
2116
]

src/web/presentation/api/views.py

Lines changed: 1 addition & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,11 @@
11
import logging
22

33
from django.views.generic import TemplateView
4-
from drf_spectacular.utils import (
5-
PolymorphicProxySerializer,
6-
extend_schema,
7-
extend_schema_view,
8-
inline_serializer,
9-
)
4+
from drf_spectacular.utils import extend_schema
105
from huey.contrib.djhuey import HUEY
11-
from rest_framework import serializers as drf_serializers
126
from rest_framework import status
13-
from rest_framework.permissions import IsAuthenticated
147
from rest_framework.response import Response
158
from rest_framework.views import APIView
16-
from rest_framework_simplejwt.authentication import JWTAuthentication
17-
18-
from domain.exceptions.offer_errors import OfferDoesNotExist
19-
from infrastructure.authentication.api_key_authentication import (
20-
ApiKeyAuthentication,
21-
UserRateThrottleExceptApiKey,
22-
)
23-
from infrastructure.di.ingestion.ingestion_factory import create_ingestion_container
24-
from presentation.ingestion.serializers import TokenErrorSerializer
259

2610
logger = logging.getLogger(__name__)
2711

@@ -35,56 +19,6 @@ def get_context_data(self, **kwargs):
3519
)
3620

3721

38-
class ArchiveOfferSuccessSerializer(drf_serializers.Serializer):
39-
status = drf_serializers.CharField()
40-
41-
42-
@extend_schema_view(
43-
post=extend_schema(
44-
request=None,
45-
summary="Archiver une offre par référence",
46-
description=(
47-
"Archive une offre selon sa référence. "
48-
"Accepte une authentification JWT ou par clé d'API."
49-
),
50-
tags=["offres"],
51-
responses={
52-
200: ArchiveOfferSuccessSerializer,
53-
401: PolymorphicProxySerializer(
54-
component_name="ArchiveOffer401Error",
55-
serializers=[
56-
TokenErrorSerializer,
57-
inline_serializer(
58-
name="ArchiveOfferUnauthorized",
59-
fields={"detail": drf_serializers.CharField()},
60-
),
61-
],
62-
resource_type_field_name=None,
63-
),
64-
404: inline_serializer(
65-
name="ArchiveOfferNotFound",
66-
fields={"detail": drf_serializers.CharField()},
67-
),
68-
},
69-
)
70-
)
71-
class ArchiveOffersView(APIView):
72-
authentication_classes = [JWTAuthentication, ApiKeyAuthentication]
73-
permission_classes = [IsAuthenticated]
74-
throttle_classes = [UserRateThrottleExceptApiKey]
75-
76-
serializer_class = ArchiveOfferSuccessSerializer
77-
78-
def post(self, request, reference: str):
79-
container = create_ingestion_container()
80-
use_case = container.archive_offer_by_reference_usecase()
81-
try:
82-
use_case.execute(reference)
83-
except OfferDoesNotExist:
84-
return Response({"detail": "Not found."}, status=status.HTTP_404_NOT_FOUND)
85-
return Response({"status": "ok"}, status=status.HTTP_200_OK)
86-
87-
8822
@extend_schema(exclude=True)
8923
class HueyHealthView(APIView):
9024
def get(self, request):

src/web/presentation/ingestion/serializers.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,3 +60,7 @@ class ListOffersFiltersSerializer(serializers.Serializer):
6060

6161
class ListOffersErrorSerializer(serializers.Serializer):
6262
error = serializers.CharField
63+
64+
65+
class ArchiveOfferSuccessSerializer(serializers.Serializer):
66+
status = serializers.CharField()
Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,19 @@
11
from django.urls import path
22

3-
from presentation.ingestion.views import ConcoursUploadView, OffersListView
3+
from presentation.ingestion.views import (
4+
ArchiveOffersView,
5+
ConcoursUploadView,
6+
OffersListView,
7+
)
48

59
app_name = "ingestion"
610

711
urlpatterns = [
812
path("concours/upload/", ConcoursUploadView.as_view(), name="concours_upload"),
913
path("offers/", OffersListView.as_view(), name="offers_list"),
14+
path(
15+
"offers/<str:reference>/archive",
16+
ArchiveOffersView.as_view(),
17+
name="offers_archive",
18+
),
1019
]

src/web/presentation/ingestion/views.py

Lines changed: 59 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,29 @@
22

33
import polars as pl
44
from asgiref.sync import async_to_sync
5-
from drf_spectacular.utils import PolymorphicProxySerializer, extend_schema
5+
from drf_spectacular.utils import (
6+
PolymorphicProxySerializer,
7+
extend_schema,
8+
extend_schema_view,
9+
inline_serializer,
10+
)
611
from pydantic import ValidationError
12+
from rest_framework import serializers as drf_serializers
713
from rest_framework import status
814
from rest_framework.parsers import FormParser, MultiPartParser
915
from rest_framework.response import Response
1016
from rest_framework.views import APIView
17+
from rest_framework_simplejwt.authentication import JWTAuthentication
1118

1219
from application.ingestion.interfaces.list_offers_input import GetFilteredOffersInput
1320
from application.ingestion.interfaces.load_documents_input import LoadDocumentsInput
1421
from application.ingestion.interfaces.load_operation_type import LoadOperationType
1522
from domain.entities.document import Document, DocumentType
23+
from domain.exceptions.offer_errors import OfferDoesNotExist
24+
from infrastructure.authentication.api_key_authentication import (
25+
ApiKeyAuthentication,
26+
UserRateThrottleExceptApiKey,
27+
)
1628
from infrastructure.di.ingestion.ingestion_factory import create_ingestion_container
1729
from presentation.ingestion.openapi import (
1830
CONCOURS_UPLOAD_DESCRIPTION,
@@ -23,6 +35,7 @@
2335
from presentation.ingestion.pagination import IngestionPagination
2436
from presentation.ingestion.schemas import ConcoursRowSchema
2537
from presentation.ingestion.serializers import (
38+
ArchiveOfferSuccessSerializer,
2639
ConcoursUploadResponseSerializer,
2740
FileErrorSerializer,
2841
ListOffersErrorSerializer,
@@ -353,3 +366,48 @@ def get(self, request):
353366
return Response(
354367
serializer.data, status=status.HTTP_500_INTERNAL_SERVER_ERROR
355368
)
369+
370+
371+
@extend_schema_view(
372+
post=extend_schema(
373+
request=None,
374+
summary="Archiver une offre par référence",
375+
description=(
376+
"Archive une offre selon sa référence. "
377+
"Accepte une authentification JWT ou par clé d'API."
378+
),
379+
tags=["offres"],
380+
responses={
381+
200: ArchiveOfferSuccessSerializer,
382+
401: PolymorphicProxySerializer(
383+
component_name="ArchiveOffer401Error",
384+
serializers=[
385+
TokenErrorSerializer,
386+
inline_serializer(
387+
name="ArchiveOfferUnauthorized",
388+
fields={"detail": drf_serializers.CharField()},
389+
),
390+
],
391+
resource_type_field_name=None,
392+
),
393+
404: inline_serializer(
394+
name="ArchiveOfferNotFound",
395+
fields={"detail": drf_serializers.CharField()},
396+
),
397+
},
398+
)
399+
)
400+
class ArchiveOffersView(APIView):
401+
authentication_classes = [JWTAuthentication, ApiKeyAuthentication]
402+
throttle_classes = [UserRateThrottleExceptApiKey]
403+
404+
serializer_class = ArchiveOfferSuccessSerializer
405+
406+
def post(self, request, reference: str):
407+
container = create_ingestion_container()
408+
use_case = container.archive_offer_by_reference_usecase()
409+
try:
410+
use_case.execute(reference)
411+
except OfferDoesNotExist:
412+
return Response({"detail": "Not found."}, status=status.HTTP_404_NOT_FOUND)
413+
return Response({"status": "ok"}, status=status.HTTP_200_OK)

src/web/tests/ingestion/presentation/views/test_archive_offers_view.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111

1212

1313
def make_url(reference: str = REFERENCE) -> str:
14-
return reverse("api:offers_archive", kwargs={"reference": reference})
14+
return reverse("ingestion:offers_archive", kwargs={"reference": reference})
1515

1616

1717
@pytest.fixture
@@ -24,7 +24,8 @@ def mock_container(use_case):
2424
container = MagicMock()
2525
container.archive_offer_by_reference_usecase.return_value = use_case
2626
with patch(
27-
"presentation.api.views.create_ingestion_container", return_value=container
27+
"presentation.ingestion.views.create_ingestion_container",
28+
return_value=container,
2829
):
2930
yield container
3031

0 commit comments

Comments
 (0)