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

✨(api) add dynamic Status and Session models + API endpoints #22

Merged
merged 4 commits into from
Apr 11, 2024
Merged
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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ and this project adheres to

### Added

- Defined dynamic status model
- Defined `/statique` endpoints and models

### Changed
Expand Down
5 changes: 3 additions & 2 deletions src/api/qualicharge/api/v1/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
from qualicharge.auth.oidc import get_token
from qualicharge.exceptions import OIDCAuthenticationError, OIDCProviderException

from .routers import auth, statique
from .routers import auth, dynamic, static

logger = logging.getLogger(__name__)

Expand All @@ -29,4 +29,5 @@ async def authentication_exception_handler(


app.include_router(auth.router)
app.include_router(statique.router)
app.include_router(static.router)
app.include_router(dynamic.router)
49 changes: 49 additions & 0 deletions src/api/qualicharge/api/v1/routers/dynamic.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
"""QualiCharge API v1 dynamique router."""

import logging
from typing import Annotated, List

from fastapi import APIRouter, Path, status

from qualicharge.models.dynamic import Session, Status

logger = logging.getLogger(__name__)

router = APIRouter(
prefix="/dynamique",
tags=["IRVE Dynamique"],
)


@router.get("/status/", tags=["Status"])
async def list_statuses() -> List[Status]:
"""List last known point of charge statuses."""
return []


@router.get("/status/{id_pdc_itinerance}", tags=["Status"])
async def read_status(
id_pdc_itinerance: Annotated[
str,
Path(
description=(
"L'identifiant du point de recharge délivré selon les modalités "
"définies à l'article 10 du décret n° 2017-26 du 12 janvier 2017."
),
),
],
) -> Status:
"""Read last known point of charge status."""
raise NotImplementedError


@router.post("/status/", status_code=status.HTTP_201_CREATED, tags=["Status"])
async def create_status(status: Status) -> Status:
"""Create a status."""
raise NotImplementedError


@router.post("/session/", status_code=status.HTTP_201_CREATED, tags=["Session"])
async def create_session(session: Session) -> Session:
"""Create a session."""
raise NotImplementedError
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@

router = APIRouter(
prefix="/statique",
tags=["IRVE Statique schema"],
tags=["IRVE Statique"],
)


Expand Down
13 changes: 13 additions & 0 deletions src/api/qualicharge/factories/dynamic.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
"""QualiCharge dynamic factories."""

from polyfactory.factories.pydantic_factory import ModelFactory

from ..models.dynamic import Session, Status


class SessionFactory(ModelFactory[Session]):
"""Session model factory."""


class StatusFactory(ModelFactory[Status]):
"""Status model factory."""
55 changes: 55 additions & 0 deletions src/api/qualicharge/models/dynamic.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
"""QualiCharge dynamic odels."""

from enum import StrEnum
from typing import Optional

from pydantic import BaseModel, Field
from pydantic.types import PastDatetime
from typing_extensions import Annotated


class EtatPDCEnum(StrEnum):
"""Status.etat_pdc field enum."""

EN_SERVICE = "en_service"
HORS_SERVICE = "hors_service"
INCONNU = "inconnu"


class OccupationPDCEnum(StrEnum):
"""Status.occupation_pdc field enum."""

LIBRE = "libre"
OCCUPE = "occupe"
RESERVE = "reserve"
INCONNU = "inconnu"


class EtatPriseEnum(StrEnum):
"""Status.etat_prise_* fields enum."""

FONCTIONNEL = "fonctionnel"
HORS_SERVICE = "hors_service"
INCONNU = "inconnu"


class Status(BaseModel):
"""IRVE dynamic model: point of charge status."""

id_pdc_itinerance: Annotated[str, Field(pattern="^[A-Z]{2}[A-Z0-9]{4,33}$")]
etat_pdc: EtatPDCEnum
occupation_pdc: OccupationPDCEnum
horodatage: PastDatetime
etat_prise_type_2: Optional[EtatPriseEnum]
etat_prise_type_combo_ccs: Optional[EtatPriseEnum]
etat_prise_type_chademo: Optional[EtatPriseEnum]
etat_prise_type_ef: Optional[EtatPriseEnum]


class Session(BaseModel):
"""IRVE dynamic model: point of charge sessions."""

id_pdc_itinerance: Annotated[str, Field(pattern="^[A-Z]{2}[A-Z0-9]{4,33}$")]
start: PastDatetime
end: PastDatetime
energy: float
20 changes: 20 additions & 0 deletions src/api/tests/models/test_dynamic.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
"""QualiCharge dynamic models tests."""

from datetime import datetime

from qualicharge.factories.dynamic import SessionFactory, StatusFactory


def test_session_model():
"""Test the dynamic Session model."""
session = SessionFactory.build()

assert session.start < datetime.now()
assert session.end < datetime.now()


def test_status_model():
"""Test the dynamic Status model."""
status = StatusFactory.build()

assert status.horodatage < datetime.now()