Add download api (CSV)

This commit is contained in:
phil 2024-04-04 00:35:18 +05:30
parent 8b7081df67
commit d09099acac
2 changed files with 80 additions and 1 deletions

77
src/gisaf/api/download.py Normal file
View file

@ -0,0 +1,77 @@
import logging
import io
from typing import Annotated
from fastapi import (Depends, APIRouter, HTTPException, status, Response)
from fastapi.responses import FileResponse, StreamingResponse
from sqlmodel import select
from sqlalchemy.orm import selectinload, joinedload
from gisaf.database import pandas_query, fastapi_db_session as db_session
from gisaf.models.geo_models_base import GeoModel, PlottableModel
from gisaf.security import (
Token, authenticate_user, get_current_active_user, create_access_token,
)
from gisaf.models.authentication import (User, UserRead, Role, RoleRead)
from gisaf.registry import registry, NotInRegistry
logger = logging.getLogger(__name__)
api = APIRouter(
tags=["download"],
# dependencies=[Depends(get_token_header)],
responses={404: {"description": "Not found"}},
)
@api.get('/csv/{store}/{model_id}/{value}/{resample}',
responses={
200: {
"content": {
"text/csv": {}
}
}
})
async def download_csv(
store: str, model_id: int, value: str, resample: str,
db_session: db_session,
user: Annotated[UserRead, Depends(get_current_active_user)]
) -> StreamingResponse:
try:
store_record = registry.stores.loc[store]
model: type[GeoModel] = store_record.model
values_model = registry.values_for_model[model][0]
except KeyError:
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND)
## Check if there's a custom getter
custom_getter = getattr(values_model, f'get_{value}', None)
if custom_getter:
df = await custom_getter(model_id)
else:
df = await values_model.get_as_dataframe(model_id=model_id, with_only_columns=[value])
if len(df) == 0:
raise HTTPException(status.HTTP_204_NO_CONTENT)
if resample and resample != '0':
value_defs = [v for v in values_model.values if v['name'] == value]
if len(value_defs) > 0 and 'agg' in value_defs[0]:
resampling_method = value_defs[0]['agg']
else:
resampling_method = 'mean'
df = df.resample(resample).agg(resampling_method)
if len(df) > 0:
df.reset_index(inplace=True)
query = select(model).where(model.id == model_id).options(
*(joinedload(jt) for jt in model.selectinload()))
response = await db_session.exec(query)
item = response.one()
filename = f'"{item.caption}-{value}-{resample}.csv"'
filename = f'{item.__class__.__name__}-{value}-{resample}.csv'
stream = io.StringIO()
df.reset_index().to_csv(stream,
index=False,
date_format='%d/%m/%Y %H:%M',
float_format=values_model.float_format)
response = Response(stream.getvalue(),
headers={
'Content-Disposition': f"attachment; filename={filename}"
})
return response

View file

@ -14,6 +14,7 @@ from gisaf.api.geoapi import api as geoapi
from gisaf.api.admin import api as admin_api from gisaf.api.admin import api as admin_api
from gisaf.api.dashboard import api as dashboard_api from gisaf.api.dashboard import api as dashboard_api
from gisaf.api.map import api as map_api from gisaf.api.map import api as map_api
from gisaf.api.download import api as download_api
from gisaf.plugins import manager as plugin_manger from gisaf.plugins import manager as plugin_manger
logging.basicConfig(level=conf.gisaf.debugLevel) logging.basicConfig(level=conf.gisaf.debugLevel)
@ -45,4 +46,5 @@ app.include_router(api, prefix="/api")
app.include_router(geoapi, prefix="/api/gj") app.include_router(geoapi, prefix="/api/gj")
app.include_router(admin_api, prefix="/api/admin") app.include_router(admin_api, prefix="/api/admin")
app.include_router(dashboard_api, prefix="/api/dashboard") app.include_router(dashboard_api, prefix="/api/dashboard")
app.include_router(map_api, prefix='/api/map') app.include_router(map_api, prefix='/api/map')
app.include_router(download_api, prefix='/api/download')