diff --git a/src/backend/app/db/models.py b/src/backend/app/db/models.py index 134894985..e17bf4bce 100644 --- a/src/backend/app/db/models.py +++ b/src/backend/app/db/models.py @@ -1750,8 +1750,8 @@ class DbGeometryLog(BaseModel): geom: dict status: GeomStatus - project_id: Optional[int] - task_id: Optional[int] + project_id: Optional[int] = None + task_id: Optional[int] = None @classmethod async def create( @@ -1792,13 +1792,22 @@ async def create( async def delete( cls, db: Connection, + project_id: int, id: int, ) -> bool: """Delete a geometry.""" async with db.cursor() as cur: await cur.execute( """ - DELETE FROM geometrylog WHERE id = %(id)s; + DELETE FROM geometrylog WHERE project_id=%(project_id)s AND id = %(id)s; """, - {"id": id}, + {"project_id": project_id, "id": id}, ) + if cur.rowcount == 0: + raise HTTPException( + status_code=HTTPStatus.NOT_FOUND, + detail=f""" + Geometry log with project_id {project_id} + and geom_id {id} not found. + """, + ) diff --git a/src/backend/app/projects/project_routes.py b/src/backend/app/projects/project_routes.py index 159b558fb..f66b1b050 100644 --- a/src/backend/app/projects/project_routes.py +++ b/src/backend/app/projects/project_routes.py @@ -49,7 +49,7 @@ from app.auth.auth_deps import login_required, mapper_login_required from app.auth.auth_schemas import AuthUser, OrgUserDict, ProjectUserDict from app.auth.providers.osm import check_osm_user, init_osm_auth -from app.auth.roles import mapper, org_admin, project_manager +from app.auth.roles import check_access, mapper, org_admin, project_manager from app.central import central_crud, central_deps, central_schemas from app.config import settings from app.db.database import db_conn @@ -1260,16 +1260,37 @@ async def download_task_boundaries( @router.post("/{project_id}/geometries") async def create_geom_log( geom_log: project_schemas.GeometryLogIn, + current_user: Annotated[ProjectUserDict, Depends(mapper)], db: Annotated[Connection, Depends(db_conn)], ): """Creates a new entry in the geometries log table. + It allows mappers to create new geom. + But needs a validator to invalidate (BAD status) the geom. + Returns: geometries (DbGeometryLog): The created geometries log entry. Raises: - HTTPException: If the geometries log creation fails. + HTTPException: If user do not have permission. + Or if the geometries log creation fails. """ + db_user = current_user.get("user") + db_project = current_user.get("project") + + if geom_log.status == "BAD": + access = await check_access( + db_user, + db, + project_id=db_project.id, + role=ProjectRole.PROJECT_MANAGER, # later change this to validator + ) + if not access: + raise HTTPException( + status_code=HTTPStatus.FORBIDDEN, + detail="You don't have permission to do this operation.", + ) + geometries = await DbGeometryLog.create(db, geom_log) if not geometries: raise HTTPException( @@ -1278,3 +1299,24 @@ async def create_geom_log( ) return geometries + + +@router.delete("/{project_id}/geometries") +async def delete_geom_log( + geom_id: int, + project_user: Annotated[ + ProjectUserDict, Depends(project_manager) + ], # later change this to validator + db: Annotated[Connection, Depends(db_conn)], +): + """Delete geometry from geometry log table. + + Returns: HTTP 204 response. + + Raises: + HTTPException: If the geometries log deletion fails. + """ + project_id = project_user.get("project").id + await DbGeometryLog.delete(db, project_id, geom_id) + log.info(f"Deletion of geom {geom_id} from project {project_id} is successful") + return Response(status_code=HTTPStatus.NO_CONTENT) diff --git a/src/backend/app/projects/project_schemas.py b/src/backend/app/projects/project_schemas.py index a73961533..f29eebf65 100644 --- a/src/backend/app/projects/project_schemas.py +++ b/src/backend/app/projects/project_schemas.py @@ -48,8 +48,8 @@ class GeometryLogIn(BaseModel): status: GeomStatus geom: dict - project_id: Optional[int] - task_id: Optional[int] + project_id: Optional[int] = None + task_id: Optional[int] = None @field_validator("geom", mode="before") @classmethod diff --git a/src/backend/migrations/002-create-geometry-log.sql b/src/backend/migrations/002-create-geometry-log.sql index 63cf42634..8a7a4615e 100644 --- a/src/backend/migrations/002-create-geometry-log.sql +++ b/src/backend/migrations/002-create-geometry-log.sql @@ -4,15 +4,20 @@ BEGIN; -CREATE TABLE geometrylog ( +CREATE TYPE public.geomstatus AS ENUM ( + 'BAD', + 'NEW' +); +ALTER TYPE public.geomstatus OWNER TO fmtm; + +CREATE TABLE public.geometrylog ( id SERIAL PRIMARY KEY, geom GEOMETRY NOT NULL, status geomstatus, project_id int, task_id int ); - -ALTER TABLE geometrylog OWNER TO fmtm; +ALTER TABLE public.geometrylog OWNER TO fmtm; -- Indexes for efficient querying CREATE INDEX idx_geometrylog ON geometrylog USING gist (geom); diff --git a/src/backend/migrations/init/fmtm_base_schema.sql b/src/backend/migrations/init/fmtm_base_schema.sql index 27bb2daaf..0fa64fe8c 100644 --- a/src/backend/migrations/init/fmtm_base_schema.sql +++ b/src/backend/migrations/init/fmtm_base_schema.sql @@ -153,6 +153,11 @@ CREATE TYPE public.entitystate AS ENUM ( ); ALTER TYPE public.entitystate OWNER TO fmtm; +CREATE TYPE public.geomstatus AS ENUM ( + 'BAD', + 'NEW' +); +ALTER TYPE public.geomstatus OWNER TO fmtm; -- Extra diff --git a/src/backend/migrations/revert/002-create-geometry-log.sql b/src/backend/migrations/revert/002-create-geometry-log.sql index d9298cb02..29818b0b5 100644 --- a/src/backend/migrations/revert/002-create-geometry-log.sql +++ b/src/backend/migrations/revert/002-create-geometry-log.sql @@ -5,6 +5,7 @@ BEGIN; DROP TABLE IF EXISTS geometrylog; +DROP TYPE IF EXISTS geomstatus; -- Commit the transaction