departements

This commit is contained in:
el 2025-07-01 18:25:10 +02:00
parent 6b53a419c9
commit 4c180fe1f8
19 changed files with 21999 additions and 431 deletions

View file

@ -1,73 +1,62 @@
# backend/routers/france_travail_offers.py
import logging
from typing import List, Optional
from fastapi import APIRouter, Depends, HTTPException, status, Query
from services.france_travail_offer_service import france_travail_offer_service
from core.security import get_current_user
from models.user import User
# Assuming these imports are still needed for your project context,
# even if not directly used in the current problem scope.
# from core.security import get_current_user
# from models.user import User
from schemas.france_travail import FranceTravailSearchResponse, OffreDetail, Offre
import logging
router = APIRouter()
logger = logging.getLogger(__name__)
@router.get("/search", response_model=FranceTravailSearchResponse)
async def search_france_travail_offers(
motsCles: Optional[str] = Query(None, description="Mots-clés de recherche (ex: 'développeur full stack')"),
commune_nom_ou_code: Optional[str] = Query(None, alias="commune", description="Nom, code postal ou code INSEE de la commune"),
distance: Optional[int] = Query(10, description="Distance maximale en km autour de la commune"),
commune_input: Optional[str] = Query(None, alias="commune", description="Nom de la commune (ex: 'Paris', 'Marseille'). Si spécifié, le code départemental sera automatiquement dérivé."),
distance: Optional[int] = Query(10, description="Distance maximale en km autour de la commune ou du code postal. Applicable avec 'commune' ou 'codePostal', 'latitude'/'longitude'."),
codePostal: Optional[str] = Query(None, description="Code postal spécifique (ex: '75001')"),
latitude: Optional[float] = Query(None, description="Latitude du point de recherche (ex: 48.8566)"),
longitude: Optional[float] = Query(None, description="Longitude du point de recherche (ex: 2.3522)"),
# codeDepartement: Optional[str] = Query(None, description="Code départemental sur 2 chiffres (ex: '75' pour Paris). Prioritaire sur les autres paramètres de localisation."), # Ce paramètre est maintenant géré en interne par le service
page: int = Query(0, description="Numéro de la page de résultats (commence à 0)"),
limit: int = Query(15, description="Nombre d'offres par page (max 100 pour l'API France Travail)"), # Max 100 est une limite courante pour une seule requête à l'API FT
contrat: Optional[str] = Query(None, description="Type de contrat (ex: 'CDI', 'CDD', 'MIS')"),
experience: Optional[str] = Query(None, description="Niveau d'expérience (ex: '1' pour débutant, '2' pour 1-3 ans, '3' pour >3 ans)"),
current_user: User = Depends(get_current_user)
limit: int = Query(15, description="Nombre d'offres par page (max 100 pour l'API France Travail)"),
contrat: Optional[str] = Query(None, description="Type de contrat (ex: 'CDI', 'CDD', 'MIS'). Plusieurs séparés par des virgules."),
experience: Optional[str] = Query(None, description="Niveau d'expérience (ex: 'E' pour expérimenté, 'D' pour débutant). Plusieurs séparés par des virgules.")
# current_user: User = Depends(get_current_user) # Décommentez si l'authentification est nécessaire
):
"""
Recherche des offres d'emploi via l'API France Travail.
Convertit le nom de ville en code INSEE si nécessaire et gère la pagination.
Nécessite une authentification.
La localisation peut être spécifiée par commune (le département sera dérivé), code postal, ou latitude/longitude.
"""
if limit > 100: # La limite de l'API France Travail pour 'range' est souvent 150 ou 100 items par requête.
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail="La limite de résultats par page ne peut pas dépasser 100 pour une seule requête API."
)
logger.info(f"Requête de recherche d'offres reçue: motsCles='{motsCles}', commune_input='{commune_input}', codePostal='{codePostal}', latitude='{latitude}', longitude='{longitude}', distance={distance}, page={page}, limit={limit}")
commune_param_for_api = None
range_start = page * limit
range_end = range_start + limit - 1
logger.info(f"Paramètre 'range' calculé pour l'API France Travail: {range_start}-{range_end}")
if commune_nom_ou_code:
if commune_nom_ou_code.isdigit() and len(commune_nom_ou_code) == 5:
commune_param_for_api = commune_nom_ou_code
logger.info(f"Recherche par code postal: {commune_nom_ou_code}")
else:
logger.info(f"Tentative de récupération du code INSEE pour la ville: {commune_nom_ou_code}")
insee_code = await france_travail_offer_service.get_insee_code_for_commune(commune_nom_ou_code)
if not insee_code:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail=f"Code INSEE non trouvé pour la ville '{commune_nom_ou_code}'. Veuillez vérifier l'orthographe ou utiliser un code postal."
)
commune_param_for_api = insee_code
logger.info(f"Code INSEE '{insee_code}' trouvé pour '{commune_nom_ou_code}'.")
# Convertir les chaînes de contrats et expériences en listes
contrats_list = contrat.split(',') if contrat else None
experiences_list = experience.split(',') if experience else None
# Les paramètres de localisation sont passés directement au service,
# qui gérera la dérivation du département et la priorité.
if (commune_param_for_api is not None) and (distance is None):
distance = 10
# Calcul du paramètre 'range' pour l'API France Travail
start_index = page * limit
end_index = start_index + limit - 1
api_range_param = f"{start_index}-{end_index}"
logger.info(f"Paramètre 'range' calculé pour l'API France Travail: {api_range_param}")
try:
response = await france_travail_offer_service.search_offers(
motsCles=motsCles,
commune=commune_param_for_api,
commune=commune_input, # Passe le nom de la commune directement
codePostal=codePostal,
latitude=latitude,
longitude=longitude,
distance=distance,
range=api_range_param, # On passe le 'range' calculé
typeContrat=contrat,
# experience=experience # Vérifiez si ce paramètre est géré par l'API France Travail ou doit être mappé
# codeDepartement n'est plus passé ici, il est dérivé dans le service
range_start=range_start,
range_end=range_end,
typeContrat=contrats_list,
experience=experiences_list
)
return response
except RuntimeError as e:
@ -80,7 +69,7 @@ async def search_france_travail_offers(
@router.get("/{offer_id}", response_model=OffreDetail)
async def get_france_travail_offer_details(
offer_id: str,
current_user: User = Depends(get_current_user)
# current_user: User = Depends(get_current_user)
):
"""
Récupère les détails d'une offre d'emploi spécifique de l'API France Travail par son ID.
@ -93,5 +82,5 @@ async def get_france_travail_offer_details(
logger.error(f"Erreur lors de la récupération des détails de l'offre {offer_id} de France Travail: {e}")
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail=f"Impossible de récupérer les détails de l'offre: {e}"
)
detail=f"Impossible de récupérer les détails de l'offre {offer_id}: {e}"
)