ffbb-data-client 2.0.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- ffbb_api_client_v3/__init__.py +25 -0
- ffbb_data_client/__init__.py +175 -0
- ffbb_data_client/clients/__init__.py +13 -0
- ffbb_data_client/clients/api_ffbb_app_client.py +2475 -0
- ffbb_data_client/clients/ffbb_data_client.py +2789 -0
- ffbb_data_client/clients/meilisearch_client.py +218 -0
- ffbb_data_client/clients/meilisearch_ffbb_client.py +647 -0
- ffbb_data_client/config.py +153 -0
- ffbb_data_client/data/__init__.py +25 -0
- ffbb_data_client/data/collections.json +1364 -0
- ffbb_data_client/data/endpoint_discovery.json +1875 -0
- ffbb_data_client/data/indexes.json +501 -0
- ffbb_data_client/data/openapi.json +35713 -0
- ffbb_data_client/data/openapi_full.json +37622 -0
- ffbb_data_client/helpers/__init__.py +27 -0
- ffbb_data_client/helpers/http_requests_helper.py +73 -0
- ffbb_data_client/helpers/http_requests_utils.py +502 -0
- ffbb_data_client/helpers/meilisearch_client_extension.py +153 -0
- ffbb_data_client/helpers/multi_search_query_helper.py +35 -0
- ffbb_data_client/models/__init__.py +241 -0
- ffbb_data_client/models/affiche.py +45 -0
- ffbb_data_client/models/cartographie.py +82 -0
- ffbb_data_client/models/categorie.py +55 -0
- ffbb_data_client/models/categorie_type.py +42 -0
- ffbb_data_client/models/clock.py +38 -0
- ffbb_data_client/models/club_contacts.py +77 -0
- ffbb_data_client/models/code.py +7 -0
- ffbb_data_client/models/commune.py +66 -0
- ffbb_data_client/models/competition_fields.py +309 -0
- ffbb_data_client/models/competition_id.py +116 -0
- ffbb_data_client/models/competition_id_categorie.py +31 -0
- ffbb_data_client/models/competition_id_sexe.py +31 -0
- ffbb_data_client/models/competition_id_type_competition.py +27 -0
- ffbb_data_client/models/competition_id_type_competition_generique.py +24 -0
- ffbb_data_client/models/competition_origine.py +69 -0
- ffbb_data_client/models/competition_origine_categorie.py +23 -0
- ffbb_data_client/models/competition_origine_type_competition.py +14 -0
- ffbb_data_client/models/competition_origine_type_competition_generique.py +24 -0
- ffbb_data_client/models/competition_type.py +6 -0
- ffbb_data_client/models/competitions_facet_distribution.py +65 -0
- ffbb_data_client/models/competitions_facet_stats.py +14 -0
- ffbb_data_client/models/competitions_hit.py +232 -0
- ffbb_data_client/models/competitions_multi_search_query.py +40 -0
- ffbb_data_client/models/competitions_query.py +11 -0
- ffbb_data_client/models/configuration_models.py +5 -0
- ffbb_data_client/models/contact_info.py +18 -0
- ffbb_data_client/models/content_multi_search_query.py +93 -0
- ffbb_data_client/models/coordonnees.py +27 -0
- ffbb_data_client/models/coordonnees_type.py +5 -0
- ffbb_data_client/models/document_flyer.py +205 -0
- ffbb_data_client/models/document_flyer_type.py +6 -0
- ffbb_data_client/models/engagement_contacts.py +97 -0
- ffbb_data_client/models/engagements_facet_distribution.py +59 -0
- ffbb_data_client/models/engagements_facet_stats.py +14 -0
- ffbb_data_client/models/engagements_hit.py +192 -0
- ffbb_data_client/models/engagements_multi_search_query.py +41 -0
- ffbb_data_client/models/etat.py +6 -0
- ffbb_data_client/models/external_competition_id.py +42 -0
- ffbb_data_client/models/external_id.py +72 -0
- ffbb_data_client/models/facet_distribution.py +13 -0
- ffbb_data_client/models/facet_stats.py +13 -0
- ffbb_data_client/models/field_set.py +10 -0
- ffbb_data_client/models/folder.py +35 -0
- ffbb_data_client/models/formation_session.py +60 -0
- ffbb_data_client/models/formations_facet_distribution.py +61 -0
- ffbb_data_client/models/formations_facet_stats.py +14 -0
- ffbb_data_client/models/formations_hit.py +277 -0
- ffbb_data_client/models/formations_multi_search_query.py +41 -0
- ffbb_data_client/models/game_stats_model.py +57 -0
- ffbb_data_client/models/game_stats_models.py +5 -0
- ffbb_data_client/models/generic_search.py +92 -0
- ffbb_data_client/models/geo.py +27 -0
- ffbb_data_client/models/geo_sort_order.py +6 -0
- ffbb_data_client/models/get_commune_response.py +18 -0
- ffbb_data_client/models/get_competition_response.py +523 -0
- ffbb_data_client/models/get_configuration_response.py +45 -0
- ffbb_data_client/models/get_engagement_response.py +23 -0
- ffbb_data_client/models/get_entraineur_response.py +18 -0
- ffbb_data_client/models/get_formation_response.py +28 -0
- ffbb_data_client/models/get_officiel_response.py +18 -0
- ffbb_data_client/models/get_organisme_response.py +476 -0
- ffbb_data_client/models/get_poule_response.py +68 -0
- ffbb_data_client/models/get_pratique_response.py +18 -0
- ffbb_data_client/models/get_rencontre_response.py +93 -0
- ffbb_data_client/models/get_saisons_response.py +56 -0
- ffbb_data_client/models/get_salle_response.py +20 -0
- ffbb_data_client/models/get_terrain_response.py +16 -0
- ffbb_data_client/models/get_tournoi_response.py +16 -0
- ffbb_data_client/models/gradient_color.py +27 -0
- ffbb_data_client/models/hit.py +16 -0
- ffbb_data_client/models/id_engagement_equipe.py +32 -0
- ffbb_data_client/models/id_organisme_equipe.py +51 -0
- ffbb_data_client/models/id_organisme_equipe1_logo.py +28 -0
- ffbb_data_client/models/id_poule.py +27 -0
- ffbb_data_client/models/jour.py +11 -0
- ffbb_data_client/models/label.py +15 -0
- ffbb_data_client/models/labellisation.py +30 -0
- ffbb_data_client/models/live.py +192 -0
- ffbb_data_client/models/lives.py +6 -0
- ffbb_data_client/models/logo.py +28 -0
- ffbb_data_client/models/multi_search_queries.py +24 -0
- ffbb_data_client/models/multi_search_query.py +96 -0
- ffbb_data_client/models/multi_search_result_competitions.py +14 -0
- ffbb_data_client/models/multi_search_result_engagements.py +14 -0
- ffbb_data_client/models/multi_search_result_formations.py +12 -0
- ffbb_data_client/models/multi_search_result_organismes.py +12 -0
- ffbb_data_client/models/multi_search_result_pratiques.py +12 -0
- ffbb_data_client/models/multi_search_result_rencontres.py +12 -0
- ffbb_data_client/models/multi_search_result_salles.py +12 -0
- ffbb_data_client/models/multi_search_result_terrains.py +12 -0
- ffbb_data_client/models/multi_search_result_tournois.py +12 -0
- ffbb_data_client/models/multi_search_results.py +103 -0
- ffbb_data_client/models/multi_search_results_class.py +96 -0
- ffbb_data_client/models/nature_sol.py +57 -0
- ffbb_data_client/models/niveau.py +10 -0
- ffbb_data_client/models/niveau_class.py +27 -0
- ffbb_data_client/models/niveau_extractor.py +214 -0
- ffbb_data_client/models/niveau_info.py +64 -0
- ffbb_data_client/models/niveau_models.py +14 -0
- ffbb_data_client/models/niveau_type.py +10 -0
- ffbb_data_client/models/objectif.py +7 -0
- ffbb_data_client/models/organisateur.py +197 -0
- ffbb_data_client/models/organisateur_type.py +6 -0
- ffbb_data_client/models/organisme_fields.py +327 -0
- ffbb_data_client/models/organisme_id_pere.py +177 -0
- ffbb_data_client/models/organismes_facet_distribution.py +46 -0
- ffbb_data_client/models/organismes_facet_stats.py +14 -0
- ffbb_data_client/models/organismes_hit.py +196 -0
- ffbb_data_client/models/organismes_multi_search_query.py +41 -0
- ffbb_data_client/models/organismes_query.py +8 -0
- ffbb_data_client/models/phase_code.py +23 -0
- ffbb_data_client/models/poule.py +35 -0
- ffbb_data_client/models/poule_fields.py +261 -0
- ffbb_data_client/models/poule_rencontre_item_model.py +69 -0
- ffbb_data_client/models/poules_models.py +6 -0
- ffbb_data_client/models/poules_query.py +9 -0
- ffbb_data_client/models/pratique.py +7 -0
- ffbb_data_client/models/pratiques_facet_distribution.py +29 -0
- ffbb_data_client/models/pratiques_facet_stats.py +14 -0
- ffbb_data_client/models/pratiques_hit.py +310 -0
- ffbb_data_client/models/pratiques_hit_type.py +9 -0
- ffbb_data_client/models/pratiques_multi_search_query.py +41 -0
- ffbb_data_client/models/pratiques_type_class.py +45 -0
- ffbb_data_client/models/publication_internet.py +6 -0
- ffbb_data_client/models/purple_logo.py +24 -0
- ffbb_data_client/models/query_fields_manager.py +75 -0
- ffbb_data_client/models/ranking_engagement.py +41 -0
- ffbb_data_client/models/rankings_models.py +6 -0
- ffbb_data_client/models/rencontres_engagement.py +23 -0
- ffbb_data_client/models/rencontres_facet_distribution.py +65 -0
- ffbb_data_client/models/rencontres_facet_stats.py +14 -0
- ffbb_data_client/models/rencontres_hit.py +271 -0
- ffbb_data_client/models/rencontres_multi_search_query.py +41 -0
- ffbb_data_client/models/saison.py +23 -0
- ffbb_data_client/models/saison_fields.py +36 -0
- ffbb_data_client/models/saisons_models.py +6 -0
- ffbb_data_client/models/saisons_query.py +9 -0
- ffbb_data_client/models/salle.py +56 -0
- ffbb_data_client/models/salles_facet_distribution.py +14 -0
- ffbb_data_client/models/salles_facet_stats.py +14 -0
- ffbb_data_client/models/salles_hit.py +153 -0
- ffbb_data_client/models/salles_multi_search_query.py +40 -0
- ffbb_data_client/models/sexe.py +9 -0
- ffbb_data_client/models/sexe_class.py +31 -0
- ffbb_data_client/models/source.py +5 -0
- ffbb_data_client/models/status.py +5 -0
- ffbb_data_client/models/team_engagement.py +56 -0
- ffbb_data_client/models/team_ranking.py +108 -0
- ffbb_data_client/models/terrains_categorie_championnat_3x3_libelle.py +5 -0
- ffbb_data_client/models/terrains_facet_distribution.py +41 -0
- ffbb_data_client/models/terrains_facet_stats.py +14 -0
- ffbb_data_client/models/terrains_hit.py +223 -0
- ffbb_data_client/models/terrains_multi_search_query.py +42 -0
- ffbb_data_client/models/terrains_name.py +5 -0
- ffbb_data_client/models/terrains_sexe_enum.py +7 -0
- ffbb_data_client/models/terrains_storage.py +5 -0
- ffbb_data_client/models/tournoi_type_class.py +35 -0
- ffbb_data_client/models/tournoi_type_enum.py +7 -0
- ffbb_data_client/models/tournoi_types_3x3.py +43 -0
- ffbb_data_client/models/tournoi_types_3x3_libelle.py +60 -0
- ffbb_data_client/models/tournoi_types_3x3_libelle_enum.py +10 -0
- ffbb_data_client/models/tournois_facet_distribution.py +41 -0
- ffbb_data_client/models/tournois_facet_stats.py +14 -0
- ffbb_data_client/models/tournois_hit.py +132 -0
- ffbb_data_client/models/tournois_hit_type.py +5 -0
- ffbb_data_client/models/tournois_libelle.py +7 -0
- ffbb_data_client/models/tournois_multi_search_query.py +40 -0
- ffbb_data_client/models/type_association.py +23 -0
- ffbb_data_client/models/type_association_libelle.py +30 -0
- ffbb_data_client/models/type_class.py +23 -0
- ffbb_data_client/models/type_competition.py +8 -0
- ffbb_data_client/models/type_competition_generique.py +31 -0
- ffbb_data_client/models/type_enum.py +7 -0
- ffbb_data_client/models/type_league.py +6 -0
- ffbb_data_client/py.typed +0 -0
- ffbb_data_client/utils/__init__.py +27 -0
- ffbb_data_client/utils/cache_manager.py +393 -0
- ffbb_data_client/utils/converter_utils.py +329 -0
- ffbb_data_client/utils/input_validation.py +360 -0
- ffbb_data_client/utils/retry_utils.py +478 -0
- ffbb_data_client/utils/secure_logging.py +153 -0
- ffbb_data_client/utils/token_manager.py +115 -0
- ffbb_data_client-2.0.0.dist-info/METADATA +339 -0
- ffbb_data_client-2.0.0.dist-info/RECORD +207 -0
- ffbb_data_client-2.0.0.dist-info/WHEEL +5 -0
- ffbb_data_client-2.0.0.dist-info/licenses/LICENSE.txt +201 -0
- ffbb_data_client-2.0.0.dist-info/top_level.txt +2 -0
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from dataclasses import dataclass
|
|
4
|
+
from typing import Any
|
|
5
|
+
|
|
6
|
+
from ..utils.converter_utils import (
|
|
7
|
+
from_int,
|
|
8
|
+
from_obj,
|
|
9
|
+
from_str,
|
|
10
|
+
)
|
|
11
|
+
from .external_competition_id import ExternalCompetitionID
|
|
12
|
+
from .id_organisme_equipe import IDOrganismeEquipe
|
|
13
|
+
from .id_poule import IDPoule
|
|
14
|
+
from .salle import Salle
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
@dataclass
|
|
18
|
+
class ExternalID:
|
|
19
|
+
nom_equipe1: str | None = None
|
|
20
|
+
nom_equipe2: str | None = None
|
|
21
|
+
numero_journee: int | None = None
|
|
22
|
+
competition_id: ExternalCompetitionID | None = None
|
|
23
|
+
id_organisme_equipe1: IDOrganismeEquipe | None = None
|
|
24
|
+
id_organisme_equipe2: IDOrganismeEquipe | None = None
|
|
25
|
+
salle: Salle | None = None
|
|
26
|
+
id_poule: IDPoule | None = None
|
|
27
|
+
|
|
28
|
+
@staticmethod
|
|
29
|
+
def from_dict(obj: Any) -> ExternalID:
|
|
30
|
+
assert isinstance(obj, dict)
|
|
31
|
+
nom_equipe1 = from_str(obj, "nomEquipe1")
|
|
32
|
+
nom_equipe2 = from_str(obj, "nomEquipe2")
|
|
33
|
+
numero_journee = from_int(obj, "numeroJournee")
|
|
34
|
+
competition_id = from_obj(ExternalCompetitionID.from_dict, obj, "competitionId")
|
|
35
|
+
id_organisme_equipe1 = from_obj(
|
|
36
|
+
IDOrganismeEquipe.from_dict, obj, "idOrganismeEquipe1"
|
|
37
|
+
)
|
|
38
|
+
id_organisme_equipe2 = from_obj(
|
|
39
|
+
IDOrganismeEquipe.from_dict, obj, "idOrganismeEquipe2"
|
|
40
|
+
)
|
|
41
|
+
salle = from_obj(Salle.from_dict, obj, "salle")
|
|
42
|
+
id_poule = from_obj(IDPoule.from_dict, obj, "idPoule")
|
|
43
|
+
return ExternalID(
|
|
44
|
+
nom_equipe1=nom_equipe1,
|
|
45
|
+
nom_equipe2=nom_equipe2,
|
|
46
|
+
numero_journee=numero_journee,
|
|
47
|
+
competition_id=competition_id,
|
|
48
|
+
id_organisme_equipe1=id_organisme_equipe1,
|
|
49
|
+
id_organisme_equipe2=id_organisme_equipe2,
|
|
50
|
+
salle=salle,
|
|
51
|
+
id_poule=id_poule,
|
|
52
|
+
)
|
|
53
|
+
|
|
54
|
+
def to_dict(self) -> dict:
|
|
55
|
+
result: dict = {}
|
|
56
|
+
if self.nom_equipe1 is not None:
|
|
57
|
+
result["nomEquipe1"] = self.nom_equipe1
|
|
58
|
+
if self.nom_equipe2 is not None:
|
|
59
|
+
result["nomEquipe2"] = self.nom_equipe2
|
|
60
|
+
if self.numero_journee is not None:
|
|
61
|
+
result["numeroJournee"] = str(self.numero_journee)
|
|
62
|
+
if self.competition_id is not None:
|
|
63
|
+
result["competitionId"] = self.competition_id.to_dict()
|
|
64
|
+
if self.id_organisme_equipe1 is not None:
|
|
65
|
+
result["idOrganismeEquipe1"] = self.id_organisme_equipe1.to_dict()
|
|
66
|
+
if self.id_organisme_equipe2 is not None:
|
|
67
|
+
result["idOrganismeEquipe2"] = self.id_organisme_equipe2.to_dict()
|
|
68
|
+
if self.salle is not None:
|
|
69
|
+
result["salle"] = self.salle.to_dict()
|
|
70
|
+
if self.id_poule is not None:
|
|
71
|
+
result["idPoule"] = self.id_poule.to_dict()
|
|
72
|
+
return result
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
from abc import ABC, abstractmethod
|
|
2
|
+
from typing import Any
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class FacetDistribution(ABC):
|
|
6
|
+
@staticmethod
|
|
7
|
+
def from_dict(obj: Any) -> "FacetDistribution":
|
|
8
|
+
# Cannot instantiate abstract class - should be implemented by subclasses
|
|
9
|
+
assert False
|
|
10
|
+
|
|
11
|
+
@abstractmethod
|
|
12
|
+
def to_dict(self) -> dict[str, Any]:
|
|
13
|
+
return {}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
from abc import ABC, abstractmethod
|
|
2
|
+
from typing import Any
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class FacetStats(ABC):
|
|
6
|
+
@staticmethod
|
|
7
|
+
def from_dict(obj: Any) -> "FacetStats":
|
|
8
|
+
# This should be implemented by concrete subclasses
|
|
9
|
+
assert False, "FacetStats is abstract and cannot be instantiated"
|
|
10
|
+
|
|
11
|
+
@abstractmethod
|
|
12
|
+
def to_dict(self) -> dict[str, Any]:
|
|
13
|
+
return {}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from dataclasses import dataclass
|
|
4
|
+
from typing import Any
|
|
5
|
+
from uuid import UUID
|
|
6
|
+
|
|
7
|
+
from ..utils.converter_utils import (
|
|
8
|
+
from_str,
|
|
9
|
+
from_uuid,
|
|
10
|
+
)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
@dataclass
|
|
14
|
+
class Folder:
|
|
15
|
+
id: UUID | None = None
|
|
16
|
+
name: str | None = None
|
|
17
|
+
parent: str | None = None
|
|
18
|
+
|
|
19
|
+
@staticmethod
|
|
20
|
+
def from_dict(obj: Any) -> Folder:
|
|
21
|
+
assert isinstance(obj, dict)
|
|
22
|
+
id = from_uuid(obj, "id")
|
|
23
|
+
name = from_str(obj, "name")
|
|
24
|
+
parent = from_str(obj, "parent")
|
|
25
|
+
return Folder(id=id, name=name, parent=parent)
|
|
26
|
+
|
|
27
|
+
def to_dict(self) -> dict:
|
|
28
|
+
result: dict = {}
|
|
29
|
+
if self.id is not None:
|
|
30
|
+
result["id"] = str(self.id)
|
|
31
|
+
if self.name is not None:
|
|
32
|
+
result["name"] = self.name
|
|
33
|
+
if self.parent is not None:
|
|
34
|
+
result["parent"] = self.parent
|
|
35
|
+
return result
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from dataclasses import dataclass
|
|
4
|
+
from datetime import datetime
|
|
5
|
+
from typing import Any
|
|
6
|
+
|
|
7
|
+
from ..utils.converter_utils import from_datetime, from_str
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
@dataclass
|
|
11
|
+
class FormationSession:
|
|
12
|
+
"""A session within a formation (MeiliSearch denormalized data)."""
|
|
13
|
+
|
|
14
|
+
id: str | None = None
|
|
15
|
+
title: str | None = None
|
|
16
|
+
date_start: datetime | None = None
|
|
17
|
+
date_end: datetime | None = None
|
|
18
|
+
place: str | None = None
|
|
19
|
+
postal_code: str | None = None
|
|
20
|
+
reference: str | None = None
|
|
21
|
+
entity: str | None = None
|
|
22
|
+
subscribe_btn: str | None = None
|
|
23
|
+
|
|
24
|
+
@staticmethod
|
|
25
|
+
def from_dict(obj: Any) -> FormationSession:
|
|
26
|
+
if not isinstance(obj, dict):
|
|
27
|
+
raise TypeError(f"Expected dict, got {obj.__class__.__name__}")
|
|
28
|
+
return FormationSession(
|
|
29
|
+
id=from_str(obj, "id"),
|
|
30
|
+
title=from_str(obj, "title"),
|
|
31
|
+
date_start=from_datetime(obj, "date_start"),
|
|
32
|
+
date_end=from_datetime(obj, "date_end"),
|
|
33
|
+
place=from_str(obj, "place"),
|
|
34
|
+
postal_code=from_str(obj, "postal_code"),
|
|
35
|
+
reference=from_str(obj, "reference"),
|
|
36
|
+
entity=from_str(obj, "entity"),
|
|
37
|
+
subscribe_btn=from_str(obj, "subscribeBtn"),
|
|
38
|
+
)
|
|
39
|
+
|
|
40
|
+
def to_dict(self) -> dict:
|
|
41
|
+
result: dict = {}
|
|
42
|
+
if self.id is not None:
|
|
43
|
+
result["id"] = self.id
|
|
44
|
+
if self.title is not None:
|
|
45
|
+
result["title"] = self.title
|
|
46
|
+
if self.date_start is not None:
|
|
47
|
+
result["date_start"] = self.date_start.isoformat()
|
|
48
|
+
if self.date_end is not None:
|
|
49
|
+
result["date_end"] = self.date_end.isoformat()
|
|
50
|
+
if self.place is not None:
|
|
51
|
+
result["place"] = self.place
|
|
52
|
+
if self.postal_code is not None:
|
|
53
|
+
result["postal_code"] = self.postal_code
|
|
54
|
+
if self.reference is not None:
|
|
55
|
+
result["reference"] = self.reference
|
|
56
|
+
if self.entity is not None:
|
|
57
|
+
result["entity"] = self.entity
|
|
58
|
+
if self.subscribe_btn is not None:
|
|
59
|
+
result["subscribeBtn"] = self.subscribe_btn
|
|
60
|
+
return result
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from dataclasses import dataclass
|
|
4
|
+
from typing import Any
|
|
5
|
+
|
|
6
|
+
from .facet_distribution import FacetDistribution
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
@dataclass
|
|
10
|
+
class FormationsFacetDistribution(FacetDistribution):
|
|
11
|
+
domain: dict[str, int] | None = None
|
|
12
|
+
mode: dict[str, int] | None = None
|
|
13
|
+
theme: dict[str, int] | None = None
|
|
14
|
+
type: dict[str, int] | None = None
|
|
15
|
+
place: dict[str, int] | None = None
|
|
16
|
+
places: dict[str, int] | None = None
|
|
17
|
+
postal_code: dict[str, int] | None = None
|
|
18
|
+
postal_codes: dict[str, int] | None = None
|
|
19
|
+
date_start_formatted: dict[str, int] | None = None
|
|
20
|
+
date_end_formatted: dict[str, int] | None = None
|
|
21
|
+
|
|
22
|
+
@staticmethod
|
|
23
|
+
def from_dict(obj: Any) -> FormationsFacetDistribution:
|
|
24
|
+
if not isinstance(obj, dict):
|
|
25
|
+
raise TypeError(f"Expected dict, got {obj.__class__.__name__}")
|
|
26
|
+
return FormationsFacetDistribution(
|
|
27
|
+
domain=obj.get("domain"),
|
|
28
|
+
mode=obj.get("mode"),
|
|
29
|
+
theme=obj.get("theme"),
|
|
30
|
+
type=obj.get("type"),
|
|
31
|
+
place=obj.get("place"),
|
|
32
|
+
places=obj.get("places"),
|
|
33
|
+
postal_code=obj.get("postal_code"),
|
|
34
|
+
postal_codes=obj.get("postal_codes"),
|
|
35
|
+
date_start_formatted=obj.get("date_start_formatted"),
|
|
36
|
+
date_end_formatted=obj.get("date_end_formatted"),
|
|
37
|
+
)
|
|
38
|
+
|
|
39
|
+
def to_dict(self) -> dict:
|
|
40
|
+
result: dict = {}
|
|
41
|
+
if self.domain is not None:
|
|
42
|
+
result["domain"] = self.domain
|
|
43
|
+
if self.mode is not None:
|
|
44
|
+
result["mode"] = self.mode
|
|
45
|
+
if self.theme is not None:
|
|
46
|
+
result["theme"] = self.theme
|
|
47
|
+
if self.type is not None:
|
|
48
|
+
result["type"] = self.type
|
|
49
|
+
if self.place is not None:
|
|
50
|
+
result["place"] = self.place
|
|
51
|
+
if self.places is not None:
|
|
52
|
+
result["places"] = self.places
|
|
53
|
+
if self.postal_code is not None:
|
|
54
|
+
result["postal_code"] = self.postal_code
|
|
55
|
+
if self.postal_codes is not None:
|
|
56
|
+
result["postal_codes"] = self.postal_codes
|
|
57
|
+
if self.date_start_formatted is not None:
|
|
58
|
+
result["date_start_formatted"] = self.date_start_formatted
|
|
59
|
+
if self.date_end_formatted is not None:
|
|
60
|
+
result["date_end_formatted"] = self.date_end_formatted
|
|
61
|
+
return result
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import Any
|
|
4
|
+
|
|
5
|
+
from .facet_stats import FacetStats
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class FormationsFacetStats(FacetStats):
|
|
9
|
+
@staticmethod
|
|
10
|
+
def from_dict(obj: Any) -> FormationsFacetStats:
|
|
11
|
+
return FormationsFacetStats()
|
|
12
|
+
|
|
13
|
+
def to_dict(self) -> dict:
|
|
14
|
+
return super().to_dict()
|
|
@@ -0,0 +1,277 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from dataclasses import dataclass, field
|
|
4
|
+
from datetime import datetime, timedelta
|
|
5
|
+
from typing import Any
|
|
6
|
+
from uuid import UUID
|
|
7
|
+
|
|
8
|
+
from ..utils.converter_utils import (
|
|
9
|
+
from_datetime,
|
|
10
|
+
from_duration,
|
|
11
|
+
from_int,
|
|
12
|
+
from_list,
|
|
13
|
+
from_str,
|
|
14
|
+
from_uuid,
|
|
15
|
+
)
|
|
16
|
+
from .formation_session import FormationSession
|
|
17
|
+
from .hit import Hit
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
@dataclass
|
|
21
|
+
class FormationsHit(Hit):
|
|
22
|
+
id: str | None = None
|
|
23
|
+
title: str | None = None
|
|
24
|
+
type: str | None = None
|
|
25
|
+
mode: str | None = None
|
|
26
|
+
domain: str | None = None
|
|
27
|
+
theme: str | None = None
|
|
28
|
+
description: str | None = None
|
|
29
|
+
goals: str | None = None
|
|
30
|
+
public: str | None = None
|
|
31
|
+
prerequisites: str | None = None
|
|
32
|
+
content: str | None = None
|
|
33
|
+
pedagogy: str | None = None
|
|
34
|
+
certification: str | None = None
|
|
35
|
+
results: str | None = None
|
|
36
|
+
modalities: str | None = None
|
|
37
|
+
level: str | None = None
|
|
38
|
+
reference: str | None = None
|
|
39
|
+
program_id_fbi: str | None = None
|
|
40
|
+
duration_hours: timedelta | None = None
|
|
41
|
+
sessions: list[FormationSession] | None = None
|
|
42
|
+
files: list[Any] | None = None
|
|
43
|
+
image: str | None = None
|
|
44
|
+
thumbnail: str | None = None
|
|
45
|
+
mode_hidden: str | None = None
|
|
46
|
+
postal_codes: list[str] | None = None
|
|
47
|
+
places: list[str] | None = None
|
|
48
|
+
id_origin_hash: str | None = None
|
|
49
|
+
date_end: datetime | None = None
|
|
50
|
+
date_end_formatted: int | None = None
|
|
51
|
+
date_start: datetime | None = None
|
|
52
|
+
date_start_formatted: int | None = None
|
|
53
|
+
entity: str | None = None
|
|
54
|
+
formation_domain: str | None = None
|
|
55
|
+
formation_duration_hours: str | None = None
|
|
56
|
+
formation_id: UUID | None = None
|
|
57
|
+
formation_image: str | None = None
|
|
58
|
+
formation_mode: str | None = None
|
|
59
|
+
formation_theme: str | None = None
|
|
60
|
+
formation_thumbnail: str | None = None
|
|
61
|
+
formation_title: str | None = None
|
|
62
|
+
place: str | None = None
|
|
63
|
+
postal_code: str | None = None
|
|
64
|
+
reference_hidden: str | None = None
|
|
65
|
+
subscribe_btn: str | None = None
|
|
66
|
+
subscribe_button: str | None = None
|
|
67
|
+
|
|
68
|
+
lower_title: str | None = field(init=False, default=None, repr=False)
|
|
69
|
+
lower_domain: str | None = field(init=False, default=None, repr=False)
|
|
70
|
+
lower_theme: str | None = field(init=False, default=None, repr=False)
|
|
71
|
+
|
|
72
|
+
def __post_init__(self) -> None:
|
|
73
|
+
self.lower_title = self.title.lower() if self.title else None
|
|
74
|
+
self.lower_domain = self.domain.lower() if self.domain else None
|
|
75
|
+
self.lower_theme = self.theme.lower() if self.theme else None
|
|
76
|
+
|
|
77
|
+
@staticmethod
|
|
78
|
+
def from_dict(obj: Any) -> FormationsHit:
|
|
79
|
+
if not isinstance(obj, dict):
|
|
80
|
+
raise TypeError(f"Expected dict, got {obj.__class__.__name__}")
|
|
81
|
+
id = from_str(obj, "id")
|
|
82
|
+
title = from_str(obj, "title")
|
|
83
|
+
type = from_str(obj, "type")
|
|
84
|
+
mode = from_str(obj, "mode")
|
|
85
|
+
domain = from_str(obj, "domain")
|
|
86
|
+
theme = from_str(obj, "theme")
|
|
87
|
+
description = from_str(obj, "description")
|
|
88
|
+
goals = from_str(obj, "goals")
|
|
89
|
+
public = from_str(obj, "public")
|
|
90
|
+
prerequisites = from_str(obj, "prerequisites")
|
|
91
|
+
content = from_str(obj, "content")
|
|
92
|
+
pedagogy = from_str(obj, "pedagogy")
|
|
93
|
+
certification = from_str(obj, "certification")
|
|
94
|
+
results = from_str(obj, "results")
|
|
95
|
+
modalities = from_str(obj, "modalities")
|
|
96
|
+
level = from_str(obj, "level")
|
|
97
|
+
reference = from_str(obj, "reference")
|
|
98
|
+
program_id_fbi = from_str(obj, "programIdFbi")
|
|
99
|
+
duration_hours = from_duration(obj, "duration_hours")
|
|
100
|
+
sessions = from_list(FormationSession.from_dict, obj, "sessions")
|
|
101
|
+
files = from_list(lambda x: x, obj, "files")
|
|
102
|
+
image = from_str(obj, "image")
|
|
103
|
+
thumbnail = from_str(obj, "thumbnail")
|
|
104
|
+
mode_hidden = from_str(obj, "mode_hidden")
|
|
105
|
+
postal_codes = from_list(str, obj, "postal_codes")
|
|
106
|
+
places = from_list(str, obj, "places")
|
|
107
|
+
id_origin_hash = from_str(obj, "id_origin_hash")
|
|
108
|
+
date_end = from_datetime(obj, "date_end")
|
|
109
|
+
date_end_formatted = from_int(obj, "date_end_formatted")
|
|
110
|
+
date_start = from_datetime(obj, "date_start")
|
|
111
|
+
date_start_formatted = from_int(obj, "date_start_formatted")
|
|
112
|
+
entity = from_str(obj, "entity")
|
|
113
|
+
formation_domain = from_str(obj, "formation_domain")
|
|
114
|
+
formation_duration_hours = from_str(obj, "formation_duration_hours")
|
|
115
|
+
formation_id = from_uuid(obj, "formation_id")
|
|
116
|
+
formation_image = from_str(obj, "formation_image")
|
|
117
|
+
formation_mode = from_str(obj, "formation_mode")
|
|
118
|
+
formation_theme = from_str(obj, "formation_theme")
|
|
119
|
+
formation_thumbnail = from_str(obj, "formation_thumbnail")
|
|
120
|
+
formation_title = from_str(obj, "formation_title")
|
|
121
|
+
place = from_str(obj, "place")
|
|
122
|
+
postal_code = from_str(obj, "postal_code")
|
|
123
|
+
reference_hidden = from_str(obj, "reference_hidden")
|
|
124
|
+
subscribe_btn = from_str(obj, "subscribeBtn")
|
|
125
|
+
subscribe_button = from_str(obj, "subscribe_button")
|
|
126
|
+
return FormationsHit(
|
|
127
|
+
id=id,
|
|
128
|
+
title=title,
|
|
129
|
+
type=type,
|
|
130
|
+
mode=mode,
|
|
131
|
+
domain=domain,
|
|
132
|
+
theme=theme,
|
|
133
|
+
description=description,
|
|
134
|
+
goals=goals,
|
|
135
|
+
public=public,
|
|
136
|
+
prerequisites=prerequisites,
|
|
137
|
+
content=content,
|
|
138
|
+
pedagogy=pedagogy,
|
|
139
|
+
certification=certification,
|
|
140
|
+
results=results,
|
|
141
|
+
modalities=modalities,
|
|
142
|
+
level=level,
|
|
143
|
+
reference=reference,
|
|
144
|
+
program_id_fbi=program_id_fbi,
|
|
145
|
+
duration_hours=duration_hours,
|
|
146
|
+
sessions=sessions,
|
|
147
|
+
files=files,
|
|
148
|
+
image=image,
|
|
149
|
+
thumbnail=thumbnail,
|
|
150
|
+
mode_hidden=mode_hidden,
|
|
151
|
+
postal_codes=postal_codes,
|
|
152
|
+
places=places,
|
|
153
|
+
id_origin_hash=id_origin_hash,
|
|
154
|
+
date_end=date_end,
|
|
155
|
+
date_end_formatted=date_end_formatted,
|
|
156
|
+
date_start=date_start,
|
|
157
|
+
date_start_formatted=date_start_formatted,
|
|
158
|
+
entity=entity,
|
|
159
|
+
formation_domain=formation_domain,
|
|
160
|
+
formation_duration_hours=formation_duration_hours,
|
|
161
|
+
formation_id=formation_id,
|
|
162
|
+
formation_image=formation_image,
|
|
163
|
+
formation_mode=formation_mode,
|
|
164
|
+
formation_theme=formation_theme,
|
|
165
|
+
formation_thumbnail=formation_thumbnail,
|
|
166
|
+
formation_title=formation_title,
|
|
167
|
+
place=place,
|
|
168
|
+
postal_code=postal_code,
|
|
169
|
+
reference_hidden=reference_hidden,
|
|
170
|
+
subscribe_btn=subscribe_btn,
|
|
171
|
+
subscribe_button=subscribe_button,
|
|
172
|
+
)
|
|
173
|
+
|
|
174
|
+
def to_dict(self) -> dict:
|
|
175
|
+
result: dict = {}
|
|
176
|
+
if self.id is not None:
|
|
177
|
+
result["id"] = self.id
|
|
178
|
+
if self.title is not None:
|
|
179
|
+
result["title"] = self.title
|
|
180
|
+
if self.type is not None:
|
|
181
|
+
result["type"] = self.type
|
|
182
|
+
if self.mode is not None:
|
|
183
|
+
result["mode"] = self.mode
|
|
184
|
+
if self.domain is not None:
|
|
185
|
+
result["domain"] = self.domain
|
|
186
|
+
if self.theme is not None:
|
|
187
|
+
result["theme"] = self.theme
|
|
188
|
+
if self.description is not None:
|
|
189
|
+
result["description"] = self.description
|
|
190
|
+
if self.goals is not None:
|
|
191
|
+
result["goals"] = self.goals
|
|
192
|
+
if self.public is not None:
|
|
193
|
+
result["public"] = self.public
|
|
194
|
+
if self.prerequisites is not None:
|
|
195
|
+
result["prerequisites"] = self.prerequisites
|
|
196
|
+
if self.content is not None:
|
|
197
|
+
result["content"] = self.content
|
|
198
|
+
if self.pedagogy is not None:
|
|
199
|
+
result["pedagogy"] = self.pedagogy
|
|
200
|
+
if self.certification is not None:
|
|
201
|
+
result["certification"] = self.certification
|
|
202
|
+
if self.results is not None:
|
|
203
|
+
result["results"] = self.results
|
|
204
|
+
if self.modalities is not None:
|
|
205
|
+
result["modalities"] = self.modalities
|
|
206
|
+
if self.level is not None:
|
|
207
|
+
result["level"] = self.level
|
|
208
|
+
if self.reference is not None:
|
|
209
|
+
result["reference"] = self.reference
|
|
210
|
+
if self.program_id_fbi is not None:
|
|
211
|
+
result["programIdFbi"] = self.program_id_fbi
|
|
212
|
+
if self.duration_hours is not None:
|
|
213
|
+
total_seconds = int(self.duration_hours.total_seconds())
|
|
214
|
+
hours, remainder = divmod(total_seconds, 3600)
|
|
215
|
+
minutes = remainder // 60
|
|
216
|
+
result["duration_hours"] = f"{hours}h{minutes:02d}"
|
|
217
|
+
if self.sessions is not None:
|
|
218
|
+
result["sessions"] = [s.to_dict() for s in self.sessions]
|
|
219
|
+
if self.files is not None:
|
|
220
|
+
result["files"] = self.files
|
|
221
|
+
if self.image is not None:
|
|
222
|
+
result["image"] = self.image
|
|
223
|
+
if self.thumbnail is not None:
|
|
224
|
+
result["thumbnail"] = self.thumbnail
|
|
225
|
+
if self.mode_hidden is not None:
|
|
226
|
+
result["mode_hidden"] = self.mode_hidden
|
|
227
|
+
if self.postal_codes is not None:
|
|
228
|
+
result["postal_codes"] = self.postal_codes
|
|
229
|
+
if self.places is not None:
|
|
230
|
+
result["places"] = self.places
|
|
231
|
+
if self.id_origin_hash is not None:
|
|
232
|
+
result["id_origin_hash"] = self.id_origin_hash
|
|
233
|
+
if self.date_end is not None:
|
|
234
|
+
result["date_end"] = self.date_end.isoformat()
|
|
235
|
+
if self.date_end_formatted is not None:
|
|
236
|
+
result["date_end_formatted"] = self.date_end_formatted
|
|
237
|
+
if self.date_start is not None:
|
|
238
|
+
result["date_start"] = self.date_start.isoformat()
|
|
239
|
+
if self.date_start_formatted is not None:
|
|
240
|
+
result["date_start_formatted"] = self.date_start_formatted
|
|
241
|
+
if self.entity is not None:
|
|
242
|
+
result["entity"] = self.entity
|
|
243
|
+
if self.formation_domain is not None:
|
|
244
|
+
result["formation_domain"] = self.formation_domain
|
|
245
|
+
if self.formation_duration_hours is not None:
|
|
246
|
+
result["formation_duration_hours"] = self.formation_duration_hours
|
|
247
|
+
if self.formation_id is not None:
|
|
248
|
+
result["formation_id"] = str(self.formation_id)
|
|
249
|
+
if self.formation_image is not None:
|
|
250
|
+
result["formation_image"] = self.formation_image
|
|
251
|
+
if self.formation_mode is not None:
|
|
252
|
+
result["formation_mode"] = self.formation_mode
|
|
253
|
+
if self.formation_theme is not None:
|
|
254
|
+
result["formation_theme"] = self.formation_theme
|
|
255
|
+
if self.formation_thumbnail is not None:
|
|
256
|
+
result["formation_thumbnail"] = self.formation_thumbnail
|
|
257
|
+
if self.formation_title is not None:
|
|
258
|
+
result["formation_title"] = self.formation_title
|
|
259
|
+
if self.place is not None:
|
|
260
|
+
result["place"] = self.place
|
|
261
|
+
if self.postal_code is not None:
|
|
262
|
+
result["postal_code"] = self.postal_code
|
|
263
|
+
if self.reference_hidden is not None:
|
|
264
|
+
result["reference_hidden"] = self.reference_hidden
|
|
265
|
+
if self.subscribe_btn is not None:
|
|
266
|
+
result["subscribeBtn"] = self.subscribe_btn
|
|
267
|
+
if self.subscribe_button is not None:
|
|
268
|
+
result["subscribe_button"] = self.subscribe_button
|
|
269
|
+
return result
|
|
270
|
+
|
|
271
|
+
def is_valid_for_query(self, query: str) -> bool:
|
|
272
|
+
return bool(
|
|
273
|
+
not query
|
|
274
|
+
or (self.lower_title and query in self.lower_title)
|
|
275
|
+
or (self.lower_domain and query in self.lower_domain)
|
|
276
|
+
or (self.lower_theme and query in self.lower_theme)
|
|
277
|
+
)
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from ..config import MEILISEARCH_FACETS_FORMATIONS, MEILISEARCH_INDEX_FORMATIONS
|
|
4
|
+
from .formations_facet_distribution import FormationsFacetDistribution
|
|
5
|
+
from .formations_facet_stats import FormationsFacetStats
|
|
6
|
+
from .multi_search_query import MultiSearchQuery
|
|
7
|
+
from .multi_search_result_formations import FormationsMultiSearchResult
|
|
8
|
+
from .multi_search_results import MultiSearchResult
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class FormationsMultiSearchQuery(MultiSearchQuery):
|
|
12
|
+
def __init__(
|
|
13
|
+
self,
|
|
14
|
+
q: str | None,
|
|
15
|
+
limit: int | None = 10,
|
|
16
|
+
offset: int | None = 0,
|
|
17
|
+
filter: list[str] | None = None,
|
|
18
|
+
sort: list[str] | None = None,
|
|
19
|
+
):
|
|
20
|
+
super().__init__(
|
|
21
|
+
index_uid=MEILISEARCH_INDEX_FORMATIONS,
|
|
22
|
+
q=q,
|
|
23
|
+
facets=MEILISEARCH_FACETS_FORMATIONS,
|
|
24
|
+
limit=limit,
|
|
25
|
+
offset=offset,
|
|
26
|
+
filter=filter,
|
|
27
|
+
sort=sort,
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
def is_valid_result(self, result: MultiSearchResult):
|
|
31
|
+
return result and (
|
|
32
|
+
isinstance(result, FormationsMultiSearchResult)
|
|
33
|
+
and (
|
|
34
|
+
result.facet_distribution is None
|
|
35
|
+
or isinstance(result.facet_distribution, FormationsFacetDistribution)
|
|
36
|
+
)
|
|
37
|
+
and (
|
|
38
|
+
result.facet_stats is None
|
|
39
|
+
or isinstance(result.facet_stats, FormationsFacetStats)
|
|
40
|
+
)
|
|
41
|
+
)
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from dataclasses import dataclass
|
|
4
|
+
from typing import Any
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
@dataclass
|
|
8
|
+
class GameStatsModel:
|
|
9
|
+
"""Model for live game statistics from gsId field."""
|
|
10
|
+
|
|
11
|
+
match_id: str | None = None
|
|
12
|
+
current_status: str | None = None
|
|
13
|
+
current_period: str | None = None
|
|
14
|
+
|
|
15
|
+
# Score domicile (home team)
|
|
16
|
+
score_q1_home: int | None = None
|
|
17
|
+
score_q2_home: int | None = None
|
|
18
|
+
score_q3_home: int | None = None
|
|
19
|
+
score_q4_home: int | None = None
|
|
20
|
+
score_ot1_home: int | None = None
|
|
21
|
+
score_ot2_home: int | None = None
|
|
22
|
+
|
|
23
|
+
# Score extérieur (away team)
|
|
24
|
+
score_q1_out: int | None = None
|
|
25
|
+
score_q2_out: int | None = None
|
|
26
|
+
score_q3_out: int | None = None
|
|
27
|
+
score_q4_out: int | None = None
|
|
28
|
+
score_ot1_out: int | None = None
|
|
29
|
+
score_ot2_out: int | None = None
|
|
30
|
+
|
|
31
|
+
@classmethod
|
|
32
|
+
def from_dict(cls, data: dict[str, Any]) -> GameStatsModel | None:
|
|
33
|
+
"""Convert dictionary to GameStatsModel instance."""
|
|
34
|
+
if not data:
|
|
35
|
+
return None
|
|
36
|
+
|
|
37
|
+
# Handle case where data is not a dictionary
|
|
38
|
+
if not isinstance(data, dict):
|
|
39
|
+
return None
|
|
40
|
+
|
|
41
|
+
return cls(
|
|
42
|
+
match_id=data.get("matchId"),
|
|
43
|
+
current_status=data.get("currentStatus"),
|
|
44
|
+
current_period=data.get("currentPeriod"),
|
|
45
|
+
score_q1_home=data.get("score_q1_home"),
|
|
46
|
+
score_q2_home=data.get("score_q2_home"),
|
|
47
|
+
score_q3_home=data.get("score_q3_home"),
|
|
48
|
+
score_q4_home=data.get("score_q4_home"),
|
|
49
|
+
score_ot1_home=data.get("score_ot1_home"),
|
|
50
|
+
score_ot2_home=data.get("score_ot2_home"),
|
|
51
|
+
score_q1_out=data.get("score_q1_out"),
|
|
52
|
+
score_q2_out=data.get("score_q2_out"),
|
|
53
|
+
score_q3_out=data.get("score_q3_out"),
|
|
54
|
+
score_q4_out=data.get("score_q4_out"),
|
|
55
|
+
score_ot1_out=data.get("score_ot1_out"),
|
|
56
|
+
score_ot2_out=data.get("score_ot2_out"),
|
|
57
|
+
)
|