Skip to content
Closed
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
Empty file added backend/bloom/__init__.py
Empty file.
61 changes: 27 additions & 34 deletions backend/bloom/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,13 @@
from pathlib import Path

from pydantic_settings import BaseSettings, SettingsConfigDict
from typing import Any

from pydantic import (
AliasChoices,
AmqpDsn,
BaseModel,
Field,
ImportString,
PostgresDsn,
RedisDsn,
field_validator,
model_validator
)


class Settings(BaseSettings):
model_config = SettingsConfigDict(
# validate_assignment=True allows to update db_url value as soon as one of
Expand All @@ -27,44 +20,44 @@ class Settings(BaseSettings):
env_ignore_empty=True,
env_nested_delimiter='__',
env_file='.env',
env_file_encoding = 'utf-8',
env_file_encoding='utf-8',
extra='ignore'
)

# Déclaration des attributs/paramètres disponibles au sein de la class settings
postgres_user:str = Field(default='')
postgres_password:str = Field(default='')
postgres_hostname:str = Field(min_length=1,
default='localhost')
postgres_port:int = Field(gt=1024,
default=5432)
)

postgres_db:str = Field(min_length=1,max_length=32,pattern=r'^(?:[a-zA-Z]|_)[\w\d_]*$')
# Déclaration des attributs/paramètres disponibles au sein de la class settings
postgres_user: str = Field(default='')
postgres_password: str = Field(default='')
postgres_hostname: str = Field(min_length=1,
default='localhost')
postgres_port: int = Field(gt=1024,
default=5432)

postgres_db: str = Field(min_length=1, max_length=32, pattern=r'^(?:[a-zA-Z]|_)[\w\d_]*$')
srid: int = Field(default=4326)
spire_token:str = Field(default='')
data_folder:str=Field(default=str(Path(__file__).parent.parent.parent.joinpath('./data')))
db_url:str=Field(default='')
spire_token: str = Field(default='')
data_folder: str = Field(default=str(Path(__file__).parent.parent.parent.joinpath('./data')))
db_url: str = Field(default='')

redis_host: str = Field(default='localhost')
redis_port: int = Field(default=6379)
redis_cache_expiration: int = Field(default=900)
logging_level:str=Field(
default="INFO",
pattern=r'NOTSET|DEBUG|INFO|WARNING|ERROR|CRITICAL'
)

logging_level: str = Field(
default="INFO",
pattern=r'NOTSET|DEBUG|INFO|WARNING|ERROR|CRITICAL'
)

@model_validator(mode='after')
def update_db_url(self)->dict:
new_url= f"postgresql://{self.postgres_user}:"\
f"{self.postgres_password}@{self.postgres_hostname}:"\
f"{self.postgres_port}/{self.postgres_db}"
def update_db_url(self) -> dict:
new_url = f"postgresql://{self.postgres_user}:" \
f"{self.postgres_password}@{self.postgres_hostname}:" \
f"{self.postgres_port}/{self.postgres_db}"
if self.db_url != new_url:
self.db_url = new_url
self.db_url = new_url
return self


settings = Settings(_env_file=os.getenv('BLOOM_CONFIG',
Path(__file__).parent.parent.parent.joinpath('.env')),
Path(__file__).parent.parent.parent.joinpath('.env')),
_secrets_dir=os.getenv('BLOOM_SECRETS_DIR',
Path(__file__).parent.parent.parent.joinpath('./secrets')))
Path(__file__).parent.parent.parent.joinpath('./secrets')))
25 changes: 16 additions & 9 deletions backend/bloom/container.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,12 @@
from bloom.infra.repositories.repository_segment import SegmentRepository
from bloom.infra.repositories.repository_zone import ZoneRepository
from bloom.services.GetVesselsFromSpire import GetVesselsFromSpire
from bloom.usecase.Excursions import ExcursionUseCase
from bloom.usecase.GenerateAlerts import GenerateAlerts
from dependency_injector import containers, providers


class UseCases(containers.DeclarativeContainer):
class UseCasesContainer(containers.DeclarativeContainer):
config = providers.Configuration()
db_url = settings.db_url
db = providers.Singleton(
Expand Down Expand Up @@ -57,14 +58,6 @@ class UseCases(containers.DeclarativeContainer):
session_factory=db.provided.session,
)

get_spire_data_usecase = providers.Factory(GetVesselsFromSpire)

generate_alert_usecase = providers.Factory(
GenerateAlerts,
alert_repository=alert_repository,
raster_repository=raster_repository,
)

spire_ais_data_repository = providers.Factory(
SpireAisDataRepository,
session_factory=db.provided.session,
Expand All @@ -74,3 +67,17 @@ class UseCases(containers.DeclarativeContainer):
SegmentRepository,
session_factory=db.provided.session,
)
get_spire_data_usecase = providers.Factory(
GetVesselsFromSpire
)

generate_alert_usecase = providers.Factory(
GenerateAlerts,
alert_repository=alert_repository,
raster_repository=raster_repository,
)

excursion_usecase = providers.Factory(
ExcursionUseCase,
excursion_repository=excursion_repository,
)
Empty file.
Empty file.
Empty file.
Empty file.
45 changes: 11 additions & 34 deletions backend/bloom/infra/repositories/repository_excursion.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,18 +34,21 @@ def get_param_from_last_excursion(self, session: Session, vessel_id: int) -> Uni
return None
return {"arrival_port_id": result.arrival_port_id, "arrival_position": result.arrival_position}

def get_excursions_by_vessel_id(self, session: Session, vessel_id: int) -> List[Excursion]:
"""Recheche l'excursion en cours d'un bateau, c'est-à-dire l'excursion qui n'a pas de date d'arrivée"""
stmt = select(sql_model.Excursion).where(sql_model.Excursion.vessel_id == vessel_id)
result = session.execute(stmt).scalars()
if not result:
return []
def get_excursions_by_vessel_id(self, vessel_id: int) -> List[Excursion]:
with self.session_factory as session:
"""Recheche l'excursion en cours d'un bateau, c'est-à-dire l'excursion qui n'a pas de date d'arrivée"""
stmt = select(sql_model.Excursion).where(sql_model.Excursion.vessel_id == vessel_id)
result = session.execute(stmt).scalars()
if not result:
return []
return [ExcursionRepository.map_to_domain(r) for r in result]

def get_vessel_excursion_by_id(self, session: Session, vessel_id: int, excursion_id: int) -> Union[Excursion, None]:
"""Recheche l'excursion en cours d'un bateau, c'est-à-dire l'excursion qui n'a pas de date d'arrivée"""
stmt = select(sql_model.Excursion).where((sql_model.Excursion.vessel_id == vessel_id)
& (sql_model.Excursion.id == excursion_id))
stmt = select(sql_model.Excursion).where(
(sql_model.Excursion.vessel_id == vessel_id)
& (sql_model.Excursion.id == excursion_id)
)
result = session.execute(stmt).scalar()
if not result:
return None
Expand Down Expand Up @@ -164,29 +167,3 @@ def map_to_domain(excursion: sql_model.Excursion) -> Excursion:
created_at=excursion.created_at,
updated_at=excursion.updated_at
)

@staticmethod
def map_to_orm(excursion: Excursion) -> sql_model.Excursion:
return sql_model.Excursion(
id=excursion.id,
vessel_id=excursion.vessel_id,
departure_port_id=excursion.departure_port_id,
departure_at=excursion.departure_at,
departure_position=from_shape(
excursion.departure_position) if excursion.departure_position is not None else None,
arrival_port_id=excursion.arrival_port_id,
arrival_at=excursion.arrival_at,
arrival_position=from_shape(excursion.arrival_position) if excursion.arrival_position is not None else None,
excursion_duration=excursion.excursion_duration,
total_time_at_sea=excursion.total_time_at_sea,
total_time_in_amp=excursion.total_time_in_amp,
total_time_in_territorial_waters=excursion.total_time_fishing_in_territorial_waters,
total_time_in_costal_waters=excursion.total_time_fishing_in_costal_waters,
total_time_fishing=excursion.total_time_fishing,
total_time_fishing_in_amp=excursion.total_time_fishing_in_amp,
total_time_fishing_in_territorial_waters=excursion.total_time_fishing_in_territorial_waters,
total_time_fishing_in_costal_waters=excursion.total_time_fishing_in_costal_waters,
total_time_extincting_amp=excursion.total_time_extincting_amp,
created_at=excursion.created_at,
updated_at=excursion.updated_at
)
14 changes: 8 additions & 6 deletions backend/bloom/infra/repositories/repository_port.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,17 +17,19 @@ class PortRepository:
def __init__(self, session_factory: Callable) -> None:
self.session_factory = session_factory

def get_port_by_id(self, session: Session, port_id: int) -> Union[Port, None]:
entity = session.get(sql_model.Port, port_id)
def get_port_by_id(self, port_id: int) -> Union[Port, None]:
with self.session_factory() as session:
entity = session.get(sql_model.Port, port_id)
if entity is not None:
return PortRepository.map_to_domain(entity)
else:
return None

def get_all_ports(self, session: Session) -> List[Port]:
q = session.query(sql_model.Port)
if not q:
return []
def get_all_ports(self) -> List[Port]:
with self.session_factory() as session:
q = session.query(sql_model.Port)
if not q:
return []
return [PortRepository.map_to_domain(entity) for entity in q]

def get_empty_geometry_buffer_ports(self, session: Session) -> list[Port]:
Expand Down
14 changes: 14 additions & 0 deletions backend/bloom/infra/repositories/repository_zone.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,14 @@ def get_all_zones(self, session: Session) -> list[Zone]:
return []
return [ZoneRepository.map_to_domain(entity) for entity in q]

def get_all_zone_categories(self, session: Session) -> list[ZoneCategory]:
q = session.query(sql_model.Zone.category,
sql_model.Zone.sub_category).distinct()
q=session.execute(q)
if not q:
return []
return [ZoneRepository.map_to_domain(ZoneCategory(category=cat,sub_category=sub)) for cat,sub in q]

def get_all_zone_categories(self, session: Session) -> list[ZoneCategory]:
q = session.query(sql_model.Zone.category,
sql_model.Zone.sub_category).distinct()
Expand Down Expand Up @@ -75,6 +83,12 @@ def map_to_domain(zone: sql_model.Zone) -> Zone:
json_data=zone.json_data,
created_at=zone.created_at,
)
@staticmethod
def map_to_domain(category: ZoneCategory) -> ZoneCategory:
return ZoneCategory(
category=category.category,
sub_category=category.sub_category
)

@staticmethod
def map_zonecategory_to_domain(category: ZoneCategory) -> ZoneCategory:
Expand Down
Empty file.
73 changes: 73 additions & 0 deletions backend/bloom/routers/excursions.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import json
import time
from typing import List

import redis
from dependency_injector.wiring import inject, Provide
from fastapi import APIRouter, Depends

from bloom.config import settings
from bloom.container import UseCasesContainer
from bloom.domain.excursion import Excursion
from bloom.logger import logger
from bloom.usecase.Excursions import ExcursionUseCase

rd = redis.Redis(host=settings.redis_host, port=settings.redis_port, db=0)

router = APIRouter()


@router.get("/vessels/{vessel_id}/excursions")
@inject
async def list_vessel_excursions(
vessel_id: int,
nocache: bool = False,
excursion_usecase: ExcursionUseCase = Depends(
Provide[UseCasesContainer.excursion_usecase]
)
) -> List[Excursion]:
endpoint = f"/vessels/{vessel_id}/excursions"
cache = rd.get(endpoint)
start = time.time()
if cache and not nocache:
logger.debug(f"{endpoint} cached ({settings.redis_cache_expiration})s")
payload = json.loads(cache)
logger.debug(f"{endpoint} elapsed Time: {time.time() - start}")
return payload
else:
return excursion_usecase.list_vessel_excursions(vessel_id)


@router.get("/vessels/{vessel_id}/excursions/{excursions_id}")
async def get_vessel_excursion(
vessel_id: int,
excursions_id: int,
excursion_usecase: ExcursionUseCase = Depends(
Provide[UseCasesContainer.excursion_usecase]
)):
return excursion_usecase.get_excursion_by_id(vessel_id, excursions_id)


@router.get("/vessels/{vessel_id}/excursions/{excursions_id}/segments")
@inject
async def list_vessel_excursion_segments(
vessel_id: int,
excursions_id: int,
excursion_usecase: ExcursionUseCase = Depends(
Provide[UseCasesContainer.excursion_usecase]
)
):
return excursion_usecase.get_excursions_segments(vessel_id, excursions_id)


@router.get("/vessels/{vessel_id}/excursions/{excursions_id}/segments/{segment_id}")
@inject
async def get_vessel_excursion_segment(
vessel_id: int,
excursions_id: int,
segment_id: int,
excursion_usecase: ExcursionUseCase = Depends(
Provide[UseCasesContainer.excursion_usecase]
)
):
return await excursion_usecase.get_segment_by_id(vessel_id, excursions_id, segment_id)
44 changes: 44 additions & 0 deletions backend/bloom/routers/ports.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import json
import time

from redis import Redis
from dependency_injector.wiring import inject, Provide
from fastapi import APIRouter, Depends
from bloom.config import settings
from bloom.container import UseCasesContainer
from bloom.logger import logger
from bloom.usecase.Ports import PortUseCase

router = APIRouter()
redis_client = Redis(host=settings.redis_host, port=settings.redis_port, db=0)


@router.get("/ports")
@inject
async def list_ports(
nocache: bool = False,
ports_usecase: PortUseCase = Depends(
Provide[UseCasesContainer.excursion_usecase]
)
):
endpoint = f"/ports"
cache = redis_client.get(endpoint)
start = time.time()
if cache and not nocache:
logger.debug(f"{endpoint} cached ({settings.redis_cache_expiration})s")
payload = json.loads(cache)
logger.debug(f"{endpoint} elapsed Time: {time.time() - start}")
return payload
else:
return ports_usecase.list_ports()


@router.get("/ports/{port_id}")
@inject
async def get_port(
port_id: int,
ports_usecase: PortUseCase = Depends(
Provide[UseCasesContainer.excursion_usecase]
)
):
return ports_usecase.get_port_by_id(port_id)
Loading