Skip to content

Commit

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

reorg: reorg backend api folder/files + dependencies +services/api =>…
  • Loading branch information
rv2931 authored Oct 9, 2024
2 parents aff45d9 + 5514926 commit 4a2e323
Show file tree
Hide file tree
Showing 9 changed files with 101 additions and 86 deletions.
84 changes: 84 additions & 0 deletions backend/bloom/dependencies.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
from fastapi import Request, HTTPException
from bloom.config import settings
from fastapi.security import APIKeyHeader
from pydantic import BaseModel, ConfigDict, Field,conint
from pydantic.generics import GenericModel
from datetime import datetime, timedelta
from typing import Generic,TypeVar, List
from enum import Enum


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

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 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],
)

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"
78 changes: 1 addition & 77 deletions backend/bloom/domain/api.py
Original file line number Diff line number Diff line change
@@ -1,89 +1,13 @@
from fastapi import Request, HTTPException
from pydantic import BaseModel, ConfigDict, Field,conint
from pydantic import BaseModel
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],
)
8 changes: 7 additions & 1 deletion backend/bloom/domain/metrics.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
from datetime import datetime, timedelta
from enum import Enum
from bloom.domain.vessel import Vessel
from bloom.dependencies import TotalTimeActivityTypeEnum

class ResponseMetricsVesselInActivitySchema(BaseModel):
model_config = ConfigDict(from_attributes=True)
Expand Down Expand Up @@ -46,4 +47,9 @@ class ResponseMetricsZoneVisitingTimeByVesselSchema(BaseModel):

class ResponseMetricsVesselTotalTimeActivityByActivityTypeSchema(BaseModel):
vessel_id : int
total_activity_time: timedelta
total_activity_time: timedelta



class TotalTimeActivityTypeRequest(BaseModel):
type: TotalTimeActivityTypeEnum
2 changes: 1 addition & 1 deletion backend/bloom/services/api.py → backend/bloom/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
from bloom.routers.vessels import router as router_vessels
from bloom.routers.ports import router as router_ports
from bloom.routers.zones import router as router_zones
from bloom.domain.api import ( DatetimeRangeRequest,
from bloom.dependencies import ( DatetimeRangeRequest,
PaginatedRequest,OrderByRequest,
paginate,PagedResponseSchema,PageParams,
X_API_KEY_HEADER,check_apikey)
Expand Down
7 changes: 4 additions & 3 deletions backend/bloom/routers/metrics.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,12 @@
ResponseMetricsZoneVisitedSchema,
ResponseMetricsZoneVisitingTimeByVesselSchema,
ResponseMetricsVesselTotalTimeActivityByActivityTypeSchema)
from bloom.domain.api import ( DatetimeRangeRequest,
from bloom.dependencies import ( DatetimeRangeRequest,
PaginatedRequest,OrderByRequest,OrderByEnum,
paginate,PagedResponseSchema,PageParams,
X_API_KEY_HEADER, check_apikey,CachedRequest,
TotalTimeActivityTypeRequest)
X_API_KEY_HEADER, check_apikey,CachedRequest)

from bloom.domain.metrics import TotalTimeActivityTypeRequest

router = APIRouter()
rd = Redis(host=settings.redis_host, port=settings.redis_port, db=0)
Expand Down
2 changes: 1 addition & 1 deletion backend/bloom/routers/ports.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
from bloom.container import UseCases
from bloom.domain.vessel import Vessel
from bloom.logger import logger
from bloom.domain.api import ( DatetimeRangeRequest,
from bloom.dependencies import ( DatetimeRangeRequest,
PaginatedRequest,OrderByRequest,OrderByEnum,
paginate,PagedResponseSchema,PageParams,
X_API_KEY_HEADER,check_apikey,CachedRequest)
Expand Down
2 changes: 1 addition & 1 deletion backend/bloom/routers/vessels.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
from bloom.container import UseCases
from bloom.domain.vessel import Vessel
from bloom.logger import logger
from bloom.domain.api import ( DatetimeRangeRequest,
from bloom.dependencies import ( DatetimeRangeRequest,
PaginatedRequest,OrderByRequest,OrderByEnum,
paginate,PagedResponseSchema,PageParams,
X_API_KEY_HEADER,check_apikey)
Expand Down
2 changes: 1 addition & 1 deletion backend/bloom/routers/zones.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
from bloom.container import UseCases
from bloom.domain.vessel import Vessel
from bloom.logger import logger
from bloom.domain.api import ( DatetimeRangeRequest,
from bloom.dependencies import ( DatetimeRangeRequest,
PaginatedRequest,OrderByRequest,OrderByEnum,
paginate,PagedResponseSchema,PageParams,
X_API_KEY_HEADER,check_apikey)
Expand Down
2 changes: 1 addition & 1 deletion docker-compose.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ services:
- -c
- |
echo "Starting Scheduler" &&
service cron start && uvicorn bloom.services.api:app --host 0.0.0.0 --reload
service cron start && uvicorn bloom.main:app --host 0.0.0.0 --reload
volumes:
- ./:/project/
- ./data:/project/data
Expand Down

0 comments on commit 4a2e323

Please sign in to comment.