Skip to content

Commit

Permalink
Merge pull request #205 from dataforgoodfr/feat_dashboard_metric_endp…
Browse files Browse the repository at this point in the history
…oints_204

[FEAT] Add dashboard metric endpoints #204
  • Loading branch information
rv2931 authored Oct 8, 2024
2 parents 2a1b65c + 0933065 commit aff45d9
Show file tree
Hide file tree
Showing 8 changed files with 788 additions and 271 deletions.
89 changes: 89 additions & 0 deletions backend/bloom/domain/api.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
from fastapi import Request, HTTPException
from pydantic import BaseModel, ConfigDict, Field,conint
from typing import Generic,TypeVar, List
from typing_extensions import Annotated, Literal, Optional
from datetime import datetime, timedelta
from enum import Enum
import redis
from pydantic.generics import GenericModel
from fastapi.security import APIKeyHeader
from bloom.config import settings

## Reference for pagination design
## https://jayhawk24.hashnode.dev/how-to-implement-pagination-in-fastapi-feat-sqlalchemy
X_API_KEY_HEADER=APIKeyHeader(name="x-key")

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

class CachedRequest(BaseModel):
nocache:bool=False

def check_apikey(key:str):
if key != settings.api_key :
raise HTTPException(status_code=401, detail="Unauthorized")
return True

def check_cache(request:Request):
cache= rd.get(request.url.path)

class DatetimeRangeRequest(BaseModel):
start_at: datetime = Field(default=datetime.now()-timedelta(days=7))
end_at: datetime = datetime.now()

class OrderByEnum(str, Enum):
ascending = "ASC"
descending = "DESC"


class TotalTimeActivityTypeEnum(str, Enum):
total_time_at_sea: str = "Total Time at Sea"
total_time_in_amp: str = "Total Time in AMP"
total_time_in_territorial_waters: str = "Total Time in Territorial Waters"
total_time_in_costal_waters: str = "Total Time in Costal Waters"
total_time_fishing: str = "Total Time Fishing"
total_time_fishing_in_amp: str = "Total Time Fishing in AMP"
total_time_fishing_in_territorial_waters: str = "Total Time Fishing in Territorial Waters"
total_time_fishing_in_costal_waters: str = "Total Time Fishing in Costal Waters"
total_time_fishing_in_extincting_amp: str = "Total Time in Extincting AMP"

class TotalTimeActivityTypeRequest(BaseModel):
type: TotalTimeActivityTypeEnum

class OrderByRequest(BaseModel):
order: OrderByEnum = OrderByEnum.ascending

class PaginatedRequest(BaseModel):
offset: int|None = 0
limit: int|None = 100
order_by: OrderByRequest = OrderByEnum.ascending


class PageParams(BaseModel):
""" Request query params for paginated API. """
offset: conint(ge=0) = 0
limit: conint(ge=1, le=100000) = 100

T = TypeVar("T")

class PagedResponseSchema(GenericModel,Generic[T]):
total: int
limit: int
offset: int
next: str|None
previous: str|None
results: List[T]

def paginate(request: Request, page_params: PageParams, query, ResponseSchema: BaseModel) -> PagedResponseSchema[T]:
"""Paginate the query."""

print(f"{request.url.scheme}://{request.client}/{request.url.path}")
paginated_query = query.offset((page_params.offset) * page_params.limit).limit(page_params.limit).all()

return PagedResponseSchema(
total=query.count(),
offset=page_params.offset,
limit=page_params.limit,
next="",
previous="",
results=[ResponseSchema.from_orm(item) for item in paginated_query],
)
49 changes: 49 additions & 0 deletions backend/bloom/domain/metrics.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
from pydantic import BaseModel, ConfigDict
from typing import Generic,TypeVar, List
from typing_extensions import Annotated, Literal, Optional
from datetime import datetime, timedelta
from enum import Enum
from bloom.domain.vessel import Vessel

class ResponseMetricsVesselInActivitySchema(BaseModel):
model_config = ConfigDict(from_attributes=True)
vessel_id: Optional[int]
vessel_mmsi: int
vessel_ship_name: str
vessel_width: Optional[float] = None
vessel_length: Optional[float] = None
vessel_country_iso3: Optional[str] = None
vessel_type: Optional[str] = None
vessel_imo: Optional[int] = None
vessel_cfr: Optional[str] = None
vessel_external_marking: Optional[str] = None
vessel_ircs: Optional[str] = None
vessel_home_port_id: Optional[int] = None
vessel_details: Optional[str] = None
vessel_tracking_activated: Optional[bool]
vessel_tracking_status: Optional[str]
vessel_length_class: Optional[str]
vessel_check: Optional[str]
total_time_at_sea: Optional[timedelta]

class ResponseMetricsZoneVisitedSchema(BaseModel):
zone_id : int
zone_category: Optional[str]
zone_sub_category: Optional[str] = None
zone_name: str
visiting_duration: timedelta

class ResponseMetricsZoneVisitingTimeByVesselSchema(BaseModel):
zone_id : int
zone_category: str
zone_sub_category: Optional[str] = None
zone_name: str
vessel_id : int
vessel_name: str
vessel_type: Optional[str] = None
vessel_length_class: Optional[str] = None
zone_visiting_time_by_vessel: timedelta

class ResponseMetricsVesselTotalTimeActivityByActivityTypeSchema(BaseModel):
vessel_id : int
total_activity_time: timedelta
23 changes: 22 additions & 1 deletion backend/bloom/infra/database/sql_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,10 @@
PrimaryKeyConstraint
)
from sqlalchemy.dialects.postgresql import JSONB
from sqlalchemy.sql import func
from sqlalchemy.sql import func, select
from sqlalchemy.orm import mapped_column, Mapped, relationship
from typing_extensions import Annotated, Literal, Optional
from datetime import timedelta


class Vessel(Base):
Expand Down Expand Up @@ -235,3 +238,21 @@ class RelSegmentZone(Base):
segment_id = Column("segment_id", Integer, ForeignKey("fct_segment.id"), nullable=False)
zone_id = Column("zone_id", Integer, ForeignKey("dim_zone.id"), nullable=False)
created_at = Column("created_at", DateTime(timezone=True), server_default=func.now())

vessel_in_activity_request=(
select(
Vessel.id,
Excursion.vessel_id,
func.sum(Excursion.total_time_at_sea).label("total_time_at_sea")
)\
.select_from(Segment)\
.join(Excursion, Segment.excursion_id == Excursion.id)\
.join(Vessel, Excursion.vessel_id == Vessel.id)\
.group_by(Vessel.id,Excursion.vessel_id,Excursion.total_time_at_sea)\
.subquery())

class MetricsVesselInActivity(Base):
__table__ = vessel_in_activity_request
#vessel_id: Mapped[Optional[int]]
#total_time_at_sea: Mapped[Optional[timedelta]]

Loading

0 comments on commit aff45d9

Please sign in to comment.