Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(poc): add new routes on v1 #384

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions api/src/alembic/env.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@
from alembic import context
from sqlalchemy import engine_from_config, pool

from data_inclusion.api.analytics import models as _ # noqa: F401 F811
from data_inclusion.api.config import settings
from data_inclusion.api.core import db
from data_inclusion.api.decoupage_administratif import models as _ # noqa: F401 F811
from data_inclusion.api.inclusion_data import models as _ # noqa: F401 F811
from data_inclusion.api.v0.analytics import models as _ # noqa: F401 F811
from data_inclusion.api.v0.inclusion_data import models as _ # noqa: F401 F811

# this is the Alembic Config object, which provides
# access to the values within the .ini file in use.
Expand Down
23 changes: 18 additions & 5 deletions api/src/data_inclusion/api/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,10 @@
from data_inclusion.api.auth.routes import router as auth_api_router
from data_inclusion.api.config import settings
from data_inclusion.api.core import db
from data_inclusion.api.inclusion_data.routes import router as data_api_router
from data_inclusion.api.inclusion_schema.routes import router as schema_api_router
from data_inclusion.api.v0.inclusion_data.routes import router as data_api_router_v0
from data_inclusion.api.v0.inclusion_schema.routes import router as schema_api_router_v0
from data_inclusion.api.v1.inclusion_data.routes import router as data_api_router_v1
from data_inclusion.api.v1.inclusion_schema.routes import router as schema_api_router_v1

API_DESCRIPTION_PATH = Path(__file__).parent / "api_description.md"

Expand Down Expand Up @@ -53,7 +55,7 @@ def create_app() -> fastapi.FastAPI:
servers=[{"url": settings.BASE_URL, "description": settings.ENV}],
openapi_url="/api/openapi.json",
description=description,
docs_url="/api/v0/docs",
docs_url="/api/v0/docs", # TODO: check what to put here
contact={
"name": "data·inclusion",
"email": "data-inclusion@inclusion.gouv.fr",
Expand All @@ -76,10 +78,16 @@ def create_app() -> fastapi.FastAPI:

app.include_router(v0_api_router)
app.include_router(
schema_api_router,
schema_api_router_v0,
prefix="/api/v0/doc",
tags=["Documentation"],
)
app.include_router(v1_api_router)
app.include_router(
schema_api_router_v1,
prefix="/api/v1/doc",
tags=["Documentation"],
)

fastapi_pagination.add_pagination(app)

Expand All @@ -88,8 +96,13 @@ def create_app() -> fastapi.FastAPI:

v0_api_router = fastapi.APIRouter(prefix="/api/v0")

v0_api_router.include_router(data_api_router)
v0_api_router.include_router(data_api_router_v0)
v0_api_router.include_router(auth_api_router, include_in_schema=False)

v1_api_router = fastapi.APIRouter(prefix="/api/v1")

v1_api_router.include_router(data_api_router_v1)
v1_api_router.include_router(auth_api_router, include_in_schema=False)


app = create_app()
2 changes: 1 addition & 1 deletion api/src/data_inclusion/api/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

from data_inclusion.api import auth
from data_inclusion.api.decoupage_administratif.commands import import_communes
from data_inclusion.api.inclusion_data.commands import load_inclusion_data
from data_inclusion.api.v0.inclusion_data.commands import load_inclusion_data

logger = logging.getLogger(__name__)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
from sqlalchemy.dialects.postgresql import insert

from data_inclusion.api.core import db
from data_inclusion.api.inclusion_data import models
from data_inclusion.api.v0.inclusion_data import models

logger = logging.getLogger(__name__)

Expand Down
2 changes: 1 addition & 1 deletion api/src/data_inclusion/api/utils/soliguide.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

from data_inclusion.api.config import settings
from data_inclusion.api.core import db
from data_inclusion.api.inclusion_data import models
from data_inclusion.api.v0.inclusion_data import models

logger = logging.getLogger(__name__)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,20 @@

import fastapi

from data_inclusion import schema as di_schema
from data_inclusion.api.analytics.models import (
from data_inclusion.api.decoupage_administratif.constants import (
Departement,
Region,
)
from data_inclusion.api.utils import pagination
from data_inclusion.api.v0.analytics.models import (
ConsultServiceEvent,
ConsultStructureEvent,
ListServicesEvent,
ListStructuresEvent,
SearchServicesEvent,
)
from data_inclusion.api.decoupage_administratif.constants import (
Departement,
Region,
)
from data_inclusion.api.inclusion_data import schemas
from data_inclusion.api.utils import pagination
from data_inclusion.api.v0.inclusion_data import schemas
from data_inclusion.api.v0.inclusion_schema import legacy as di_schema


def save_consult_structure_event(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,10 @@
from furl import furl
from tqdm import tqdm

from data_inclusion import schema
from data_inclusion.api.config import settings
from data_inclusion.api.core import db
from data_inclusion.api.inclusion_data import models
from data_inclusion.api.v0.inclusion_data import models
from data_inclusion.api.v0.inclusion_schema import legacy as schema

logger = logging.getLogger(__name__)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,7 @@

import fastapi

from data_inclusion import schema as di_schema
from data_inclusion.api import auth
from data_inclusion.api.analytics.services import (
save_consult_service_event,
save_consult_structure_event,
save_list_services_event,
save_list_structures_event,
save_search_services_event,
)
from data_inclusion.api.config import settings
from data_inclusion.api.core import db
from data_inclusion.api.decoupage_administratif.constants import (
Expand All @@ -26,8 +18,16 @@
get_departement_by_code_or_slug,
get_region_by_code_or_slug,
)
from data_inclusion.api.inclusion_data import schemas, services
from data_inclusion.api.utils import pagination, soliguide
from data_inclusion.api.v0.analytics.services import (
save_consult_service_event,
save_consult_structure_event,
save_list_services_event,
save_list_structures_event,
save_search_services_event,
)
from data_inclusion.api.v0.inclusion_data import schemas, services
from data_inclusion.api.v0.inclusion_schema import legacy as di_schema

router = fastapi.APIRouter(tags=["Données"])

Expand Down
54 changes: 54 additions & 0 deletions api/src/data_inclusion/api/v0/inclusion_data/schemas.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
from textwrap import dedent
from typing import Annotated

from pydantic import BaseModel, ConfigDict, Field

from data_inclusion.api.v0.inclusion_schema import legacy as schema


class Source(BaseModel):
slug: str
nom: str
description: str | None


class Service(schema.Service):
model_config = ConfigDict(from_attributes=True, populate_by_name=True)

# Dont use pydantic's `HttpUrl`, because it would likely trigger validation errors
prise_rdv: str | None = None
formulaire_en_ligne: str | None = None
lien_source: str | None = None

score_qualite: Annotated[
float,
Field(
ge=0,
le=1,
description=dedent("""\
Score de qualité du service, défini et calculé par data·inclusion.
"""),
),
]


class Structure(schema.Structure):
model_config = ConfigDict(from_attributes=True, populate_by_name=True)

# Dont use pydantic's `HttpUrl`, because it would likely trigger validation errors
site_web: str | None = None
lien_source: str | None = None
accessibilite: str | None = None


class DetailedService(Service):
structure: Structure


class ServiceSearchResult(BaseModel):
service: DetailedService
distance: int | None = None


class DetailedStructure(Structure):
services: list[Service]
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,13 @@
# TODO(vmttn): handle pagination outside ?
from fastapi_pagination.ext.sqlalchemy import paginate

from data_inclusion import schema as di_schema
from data_inclusion.api.decoupage_administratif.constants import (
Departement,
Region,
)
from data_inclusion.api.decoupage_administratif.models import Commune
from data_inclusion.api.inclusion_data import models
from data_inclusion.api.v0.inclusion_data import models
from data_inclusion.api.v0.inclusion_schema import legacy as di_schema

logger = logging.getLogger(__name__)

Expand Down
Empty file.
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
from data_inclusion.schema.common import (
CodeCommune,
CodeDepartement,
CodeEPCI,
CodePostal,
CodeRegion,
CodeRna,
CodeSiren,
CodeSiret,
)
from data_inclusion.schema.frais import Frais
from data_inclusion.schema.labels_nationaux import LabelNational
from data_inclusion.schema.modes_accueil import ModeAccueil
from data_inclusion.schema.modes_orientation import (
ModeOrientationAccompagnateur,
ModeOrientationBeneficiaire,
)
from data_inclusion.schema.profils import Profil
from data_inclusion.schema.services import Service
from data_inclusion.schema.structures import Structure
from data_inclusion.schema.thematiques import Thematique
from data_inclusion.schema.typologies_de_services import TypologieService
from data_inclusion.schema.typologies_de_structures import Typologie
from data_inclusion.schema.zones_de_diffusion import ZoneDiffusionType

__all__ = [
"CodeCommune",
"CodeDepartement",
"CodeEPCI",
"CodePostal",
"CodeRegion",
"CodeRna",
"CodeSiren",
"CodeSiret",
"Frais",
"LabelNational",
"ModeAccueil",
"ModeOrientationAccompagnateur",
"ModeOrientationBeneficiaire",
"MobilisablePar",
"Profil",
"Service",
"Structure",
"Thematique",
"TypologieService",
"Typologie",
"ZoneDiffusionType",
]
77 changes: 77 additions & 0 deletions api/src/data_inclusion/api/v0/inclusion_schema/legacy/base.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import enum
import textwrap

import pydantic


def Field(*args, **kwargs):
if "description" in kwargs:
kwargs["description"] = (
textwrap.dedent(kwargs["description"].strip("\n"))
.replace("\n", " ")
.strip()
)
return pydantic.Field(*args, **kwargs)


class BaseModel(pydantic.BaseModel):
@classmethod
def model_list_json_schema(
cls,
title: str,
id: str,
description: str,
) -> dict:
adapter = pydantic.TypeAdapter(list[cls])
schema = adapter.json_schema()

return {
"title": title,
"$schema": "http://json-schema.org/draft-07/schema",
"$id": id,
"description": description,
**schema,
}


class EnhancedEnum(str, enum.Enum):
def __new__(cls, value, label, description):
obj = str.__new__(cls, value)
obj._value_ = value
obj._label = label
obj._description = (
textwrap.dedent(description).strip("\n").replace("\n", " ")
if description
else None
)

try:
if obj._description is not None:
if not obj._description[0].isupper():
raise ValueError("description must start with uppercase letter")
except ValueError as err:
raise ValueError(f"{cls.__name__}({value})'s {err}")

return obj

@classmethod
def as_dict_list(cls) -> list[dict]:
return sorted(
[
{
"value": instance.value,
"label": instance.label,
"description": instance.description,
}
for instance in cls
],
key=lambda d: d["value"],
)

@property
def label(self) -> str:
return self._label

@property
def description(self) -> str:
return self._description
Loading