Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor: remove fmtm-splitter and Update Profile Endpoints #192

Merged
merged 11 commits into from
Sep 6, 2024
Merged
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 @@ -202,13 +202,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 @@ -233,16 +235,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 @@ -277,14 +281,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