Skip to content

Commit

Permalink
Merge pull request #192 from hotosm/feat/improve-code-structure
Browse files Browse the repository at this point in the history
 Refactor: remove fmtm-splitter and Update Profile Endpoints
  • Loading branch information
nrjadkry authored Sep 6, 2024
2 parents 29449d6 + a1dceaa commit ebea3fd
Show file tree
Hide file tree
Showing 13 changed files with 566 additions and 1,046 deletions.
1 change: 1 addition & 0 deletions src/backend/app/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ def assemble_db_connection(cls, v: Optional[str], info: ValidationInfo) -> Any:
)
return pg_url

FRONTEND_URL: str = "http://localhost:3040"
S3_ENDPOINT: str = "http://s3:9000"
S3_ACCESS_KEY: Optional[str] = ""
S3_SECRET_KEY: Optional[str] = ""
Expand Down
2 changes: 0 additions & 2 deletions src/backend/app/drones/drone_logic.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@
from loguru import logger as log
from fastapi import HTTPException
from psycopg import Connection

# from asyncpg import UniqueViolationError
from typing import List
from app.drones.drone_schemas import DroneOut

Expand Down
2 changes: 1 addition & 1 deletion src/backend/app/drones/drone_routes.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ async def read_drones(
raise HTTPException(status_code=HTTPStatus.NOT_FOUND) from e


@router.post("/create_drone")
@router.post("/create-drone")
async def create_drone(
drone_info: drone_schemas.DroneIn,
db: Annotated[Connection, Depends(database.get_db)],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,9 @@ <h2>{{ task_status|capitalize }} Task Details</h2>
<p><strong>Description:</strong> {{ description }}</p>
</div>
{% if task_status == 'approved' %}
<a href="https://dronetm-dev.naxa.com.np" class="task-button"
<a
href="{{FRONTEND_URL}}/projects/{{project_id}}/tasks/{{task_id}}"
class="task-button"
>Start Mapping</a
>
{% endif %}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,9 @@ <h2>Mapping Task Details</h2>
<p><strong>Project:</strong>{{project_name}}</p>
<p><strong>Description:</strong> {{description}}</p>
</div>
<a href="dronetm.naxa.com.np" class="task-button"
<a
href="{{FRONTEND_URL}}/projects/{{project_id}}/tasks/{{task_id}}"
class="task-button"
>Visit Drone Tasking Manager</a
>
</div>
Expand Down
5 changes: 2 additions & 3 deletions src/backend/app/tasks/task_logic.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@ async def get_task_geojson(db: Connection, task_id: uuid.UUID):
status_code=HTTPStatus.NOT_FOUND, detail="Task not found"
)
return data[0]
# return json.loads(data[0]["geom"])


async def update_task_state(
Expand Down Expand Up @@ -123,8 +122,8 @@ async def request_mapping(
"task_id": str(task_id),
"user_id": str(user_id),
"comment": comment,
"unlocked_to_map_state": initial_state.name, # State.UNLOCKED_TO_MAP.name,
"request_for_map_state": final_state.name, # State.REQUEST_FOR_MAPPING.name,
"unlocked_to_map_state": initial_state.name,
"request_for_map_state": final_state.name,
},
)
result = await cur.fetchone()
Expand Down
11 changes: 8 additions & 3 deletions src/backend/app/tasks/task_routes.py
Original file line number Diff line number Diff line change
Expand Up @@ -206,13 +206,15 @@ async def new_event(
db, project["author_id"]
)
html_content = render_email_template(
template_name="mapping_requests.html",
template_name="requests.html",
context={
"name": author["name"],
"drone_operator_name": user_data.name,
"task_id": task_id,
"project_id": project_id,
"project_name": project["name"],
"description": project["description"],
"FRONTEND_URL": settings.FRONTEND_URL,
},
)
background_tasks.add_task(
Expand All @@ -238,16 +240,18 @@ async def new_event(
db, requested_user_id
)
html_content = render_email_template(
template_name="mapping_approved_or_rejected.html",
template_name="approved_or_rejected.html",
context={
"email_subject": "Mapping Request Approved",
"email_body": "We are pleased to inform you that your mapping request has been approved. Your contribution is invaluable to our efforts in improving humanitarian responses worldwide.",
"task_status": "approved",
"name": user_data.name,
"drone_operator_name": drone_operator["name"],
"task_id": task_id,
"project_id": project_id,
"project_name": project["name"],
"description": project["description"],
"FRONTEND_URL": settings.FRONTEND_URL,
},
)

Expand Down Expand Up @@ -282,14 +286,15 @@ async def new_event(
db, requested_user_id
)
html_content = render_email_template(
template_name="mapping_approved_or_rejected.html",
template_name="approved_or_rejected.html",
context={
"email_subject": "Mapping Request Rejected",
"email_body": "We are sorry to inform you that your mapping request has been rejected.",
"task_status": "rejected",
"name": user_data.name,
"drone_operator_name": drone_operator["name"],
"task_id": task_id,
"project_id": project_id,
"project_name": project["name"],
"description": project["description"],
},
Expand Down
16 changes: 14 additions & 2 deletions src/backend/app/users/user_routes.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
from app.users import user_schemas
from app.users import user_deps
from app.users import user_logic
from fastapi import APIRouter, Response, HTTPException, Depends, Request
from fastapi import APIRouter, HTTPException, Depends, Request
from typing import Annotated
from fastapi.security import OAuth2PasswordRequestForm
from app.users.user_schemas import (
Expand Down Expand Up @@ -87,7 +87,10 @@ async def update_user_profile(
if not user:
raise HTTPException(status_code=HTTPStatus.NOT_FOUND, detail="User not found")
user = await user_schemas.DbUserProfile.update(db, user_id, profile_update)
return Response(status_code=HTTPStatus.OK)
return JSONResponse(
status_code=HTTPStatus.OK,
content={"message": "User profile updated successfully"},
)


@router.get("/google-login")
Expand Down Expand Up @@ -141,10 +144,19 @@ async def my_data(
user_data: Annotated[AuthUser, Depends(login_required)],
):
"""Read access token and get user details from Google"""
# Get or create user info
user_info = await user_schemas.DbUser.get_or_create_user(db, user_data)
# Check if user profile exists
has_user_profile = await user_schemas.DbUserProfile.get_userprofile_by_userid(
db, user_info.id
)

# Convert user info to dictionary and add profile existence flag
user_info_dict = user_info.model_dump()
user_info_dict["has_user_profile"] = bool(has_user_profile)

# Merge user profile if it exists
if has_user_profile:
user_info_dict.update(has_user_profile.model_dump())

return user_info_dict
13 changes: 11 additions & 2 deletions src/backend/app/users/user_schemas.py
Original file line number Diff line number Diff line change
Expand Up @@ -99,9 +99,18 @@ class BaseUserProfile(BaseModel):

@field_validator("role", mode="after")
@classmethod
def integer_role_to_string(cls, value: UserRole) -> str:
def integer_role_to_string(cls, value: UserRole):
if isinstance(value, int):
value = UserRole(value)
return str(value.name)

@field_validator("role", mode="before")
@classmethod
def srting_role_to_integer(cls, value: UserRole) -> str:
if isinstance(value, str):
value = UserRole[value].value
return value


class UserProfileIn(BaseUserProfile):
password: Optional[str] = None
Expand Down Expand Up @@ -164,7 +173,7 @@ async def get_userprofile_by_userid(db: Connection, user_id: str):
WHERE user_id = %(user_id)s
LIMIT 1;
"""
async with db.cursor() as cur:
async with db.cursor(row_factory=class_row(DbUserProfile)) as cur:
await cur.execute(query, {"user_id": user_id})
result = await cur.fetchone()
log.info(f"Fetched user profile data: {result}")
Expand Down
46 changes: 1 addition & 45 deletions src/backend/app/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -229,50 +229,6 @@ def parse_featcol(features: Union[Feature, FeatCol, MultiPolygon, Polygon]):
return feat_col


# def merge_multipolygon(features: Union[Feature, FeatCol, MultiPolygon, Polygon]):
# """Merge multiple Polygons or MultiPolygons into a single Polygon.

# Args:
# features: geojson features to merge.

# Returns:
# A GeoJSON FeatureCollection containing the merged Polygon.
# """
# try:

# def remove_z_dimension(coord):
# """Remove z dimension from geojson."""
# return coord.pop() if len(coord) == 3 else None

# features = geojson_to_featcol(features)

# multi_polygons = []
# # handles both collection or single feature
# features = features.get("features", [features])

# for feature in features:
# list(map(remove_z_dimension, feature["geometry"]["coordinates"][0]))
# polygon = shapely.geometry.shape(feature["geometry"])
# multi_polygons.append(polygon)

# merged_polygon = unary_union(multi_polygons)
# if isinstance(merged_polygon, MultiPolygon):
# merged_polygon = merged_polygon.convex_hull

# merged_geojson = mapping(merged_polygon)
# if merged_geojson["type"] == "MultiPolygon":
# log.error(
# "Resulted GeoJSON contains disjoint Polygons. "
# "Adjacent polygons are preferred."
# )
# return geojson.FeatureCollection([geojson.Feature(geometry=merged_geojson)])
# except Exception as e:
# raise HTTPException(
# status_code=400,
# detail=f"Couldn't merge the multipolygon to polygon: {str(e)}",
# ) from e


def get_address_from_lat_lon(latitude, longitude):
"""Get address using Nominatim, using lat,lon."""
base_url = "https://nominatim.openstreetmap.org/reverse"
Expand Down Expand Up @@ -434,7 +390,7 @@ def render_email_template(template_name: str, context: dict[str, Any]) -> str:
"""

template_str = (
Path(__file__).parent / "email_templates" / template_name
Path(__file__).parent / "email_templates" / "mapping" / template_name
).read_text()
html_content = Template(template_str).render(context)
return html_content
Expand Down
3 changes: 1 addition & 2 deletions src/backend/app/waypoints/waypoint_routes.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,8 @@ async def get_task_waypoint(
"""

task_geojson = await get_task_geojson(db, task_id)
# features = task_geojson["features"][0]

project = await project_deps.get_project_by_id(project_id, db)
# project = await get_project_by_id(db, project_id)

forward_overlap = project.front_overlap if project.front_overlap else 70
side_overlap = project.side_overlap if project.side_overlap else 70
Expand Down
Loading

0 comments on commit ebea3fd

Please sign in to comment.