Skip to content

Commit

Permalink
fix: XLSForm template download endpoint for specified categories (#1441)
Browse files Browse the repository at this point in the history
  • Loading branch information
spwoodcock authored Apr 12, 2024
1 parent e9fd419 commit acee91e
Show file tree
Hide file tree
Showing 7 changed files with 40 additions and 123 deletions.
23 changes: 7 additions & 16 deletions src/backend/app/central/central_crud.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@
javarosa_to_geojson_geom,
parse_and_filter_geojson,
)
from app.models.enums import HTTPStatus
from app.models.enums import HTTPStatus, XLSFormType
from app.projects import project_schemas


Expand Down Expand Up @@ -291,31 +291,22 @@ def list_submissions(
return submissions


def get_form_list(db: Session, skip: int, limit: int):
"""Returns the list of id and title of xforms from the database."""
async def get_form_list(db: Session) -> dict:
"""Returns the dict of {id:title} for XLSForms in the database."""
try:
categories_to_filter = [
"amenities",
"camping",
"cemeteries",
"education",
"nature",
"places",
"wastedisposal",
"waterpoints",
]
include_categories = [category.value for category in XLSFormType]

sql_query = text(
"""
SELECT id, title FROM xlsforms
WHERE title NOT IN
WHERE title IN
(SELECT UNNEST(:categories));
"""
)

result = db.execute(sql_query, {"categories": categories_to_filter}).fetchall()
result = db.execute(sql_query, {"categories": include_categories}).fetchall()

result_dict = [{"id": row.id, "title": row.title} for row in result]
result_dict = {row.id: row.title for row in result}

return result_dict

Expand Down
22 changes: 5 additions & 17 deletions src/backend/app/central/central_routes.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,26 +55,14 @@ async def list_projects():

@router.get("/list-forms")
async def get_form_lists(
db: Session = Depends(database.get_db), skip: int = 0, limit: int = 100
):
"""Get a list of all XForms on ODK Central.
Option to skip a certain number of records and limit the number of
records returned.
Parameters:
skip (int): the number of records to skip before starting to retrieve records.
Defaults to 0 if not provided.
limit (int): the maximum number of records to retrieve.
Defaults to 10 if not provided.
db: Session = Depends(database.get_db),
) -> dict:
"""Get a list of all XLSForms available in FMTM.
Returns:
list[dict]: list of id:title dicts of each XForm record.
dict: JSON of {id:title} with each XLSForm record.
"""
# NOTE runs in separate thread using run_in_threadpool
forms = await run_in_threadpool(lambda: central_crud.get_form_list(db, skip, limit))
forms = await central_crud.get_form_list(db)
return forms


Expand Down
18 changes: 16 additions & 2 deletions src/backend/app/helpers/helper_routes.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@
UploadFile,
)
from fastapi.exceptions import HTTPException
from fastapi.responses import Response
from fastapi.responses import FileResponse, Response
from osm_fieldwork.xlsforms import xlsforms_path

from app.auth.osm import AuthUser, login_required
from app.central.central_crud import (
Expand All @@ -40,7 +41,7 @@
javarosa_to_geojson_geom,
parse_and_filter_geojson,
)
from app.models.enums import GeometryType, HTTPStatus
from app.models.enums import GeometryType, HTTPStatus, XLSFormType

router = APIRouter(
prefix="/helper",
Expand All @@ -49,6 +50,19 @@
)


@router.get("/download-template-xlsform")
async def download_template(
category: XLSFormType,
current_user: AuthUser = Depends(login_required),
):
"""Download an XLSForm template to fill out."""
xlsform_path = f"{xlsforms_path}/{category}.xls"
if Path(xlsform_path).exists:
return FileResponse(xlsform_path, filename="form.xls")
else:
raise HTTPException(status_code=HTTPStatus.NOT_FOUND, detail="Form not found")


@router.post("/append-geojson-properties")
async def append_required_geojson_properties(
geojson: UploadFile,
Expand Down
12 changes: 12 additions & 0 deletions src/backend/app/models/enums.py
Original file line number Diff line number Diff line change
Expand Up @@ -312,3 +312,15 @@ class GeometryType(str, Enum):
Polygon = "Polygon"
LineString = "LineString"
Point = "Point"


class XLSFormType(str, Enum):
"""Enum for XLSForm categories."""

BUILDING = "buildings"
HIGHWAYS = "highways"
HEALTH = "health"
TOILETS = "toilets"
RELIGIOUS = "religious"
LANDUSAGE = "landusage"
WATERWAYS = "waterways"
39 changes: 0 additions & 39 deletions src/backend/app/projects/project_routes.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,6 @@
from app.models.enums import TILES_FORMATS, TILES_SOURCE, HTTPStatus
from app.organisations import organisation_deps
from app.projects import project_crud, project_deps, project_schemas
from app.static import data_path
from app.submissions import submission_crud
from app.tasks import tasks_crud

Expand Down Expand Up @@ -836,20 +835,6 @@ async def update_project_form(
return project


@router.get("/download_template/")
async def download_template(
category: str,
db: Session = Depends(database.get_db),
current_user: AuthUser = Depends(mapper),
):
"""Download an XLSForm template to fill out."""
xlsform_path = f"{xlsforms_path}/{category}.xls"
if os.path.exists(xlsform_path):
return FileResponse(xlsform_path, filename="form.xls")
else:
raise HTTPException(status_code=404, detail="Form not found")


@router.get("/{project_id}/download")
async def download_project_boundary(
project_id: int,
Expand Down Expand Up @@ -1155,30 +1140,6 @@ async def get_task_status(
)


@router.get("/templates/")
async def get_template_file(
file_type: str = Query(
..., enum=["data_extracts", "form"], description="Choose file type"
),
current_user: AuthUser = Depends(login_required),
):
"""Get template file.
Args: file_type: Type of template file.
returns: Requested file as a FileResponse.
"""
file_type_paths = {
"data_extracts": f"{data_path}/template/template.geojson",
"form": f"{data_path}/template/template.xls",
}
file_path = file_type_paths.get(file_type)
filename = file_path.split("/")[-1]
return FileResponse(
file_path, media_type="application/octet-stream", filename=filename
)


@router.get(
"/project_dashboard/{project_id}", response_model=project_schemas.ProjectDashboard
)
Expand Down
23 changes: 0 additions & 23 deletions src/backend/app/static/__init__.py

This file was deleted.

26 changes: 0 additions & 26 deletions src/backend/app/static/template/template.geojson

This file was deleted.

0 comments on commit acee91e

Please sign in to comment.