diff --git a/src/backend/app/auth/roles.py b/src/backend/app/auth/roles.py index 8aadc669f5..e37029e13b 100644 --- a/src/backend/app/auth/roles.py +++ b/src/backend/app/auth/roles.py @@ -334,3 +334,61 @@ async def mapper( current_user, ProjectRole.MAPPER, ) + + +async def project_contributors( + project: Annotated[DbProject, Depends(get_project)], + db: Annotated[Connection, Depends(db_conn)], + current_user: Annotated[AuthUser, Depends(login_required)], +) -> ProjectUserDict: + """A contributor to a specific project.""" + user_id = current_user.id + project_id = project.id + org_id = project.organisation_id + + query = """ + SELECT * FROM users + WHERE id = %(user_id)s + AND ( + CASE WHEN role = 'ADMIN' THEN true + ELSE + EXISTS ( + SELECT 1 FROM organisation_managers + WHERE organisation_managers.user_id = %(user_id)s + AND organisation_managers.organisation_id = %(org_id)s + ) + OR EXISTS ( + SELECT 1 FROM user_roles + WHERE user_roles.user_id = %(user_id)s + AND user_roles.project_id = %(project_id)s + AND user_roles.role = 'PROJECT_MANAGER' + ) + OR EXISTS ( + SELECT 1 FROM projects + WHERE projects.author_id = %(user_id)s + ) + OR EXISTS ( + SELECT 1 FROM task_events + WHERE task_events.user_id = %(user_id)s + AND task_events.project_id = %(project_id)s + ) + END + ); + """ + async with db.cursor() as cur: + await cur.execute( + query, + {"user_id": user_id, "project_id": project_id, "org_id": org_id}, + ) + db_user = await cur.fetchone() + + if db_user: + return { + "user": db_user, + "project": project, + } + + raise HTTPException( + status_code=HTTPStatus.FORBIDDEN, + detail="You do not have permission to access this resource.", + ) diff --git a/src/backend/app/submissions/submission_routes.py b/src/backend/app/submissions/submission_routes.py index ab322fc15f..de30151a6c 100644 --- a/src/backend/app/submissions/submission_routes.py +++ b/src/backend/app/submissions/submission_routes.py @@ -30,7 +30,7 @@ from psycopg.rows import class_row from app.auth.auth_schemas import ProjectUserDict -from app.auth.roles import mapper, project_manager +from app.auth.roles import mapper, project_contributors, project_manager from app.central import central_crud from app.db import postgis_utils from app.db.database import db_conn @@ -63,7 +63,7 @@ async def read_submissions( @router.get("/download") async def download_submission( - project_user: Annotated[ProjectUserDict, Depends(mapper)], + project_user: Annotated[ProjectUserDict, Depends(project_contributors)], export_json: bool = True, ): """Download the submissions for a given project. @@ -365,7 +365,7 @@ async def update_review_state( @router.get("/download-submission-geojson") async def download_submission_geojson( - project_user: Annotated[ProjectUserDict, Depends(mapper)], + project_user: Annotated[ProjectUserDict, Depends(project_contributors)], ): """Download submission geojson for a specific project.""" project = project_user.get("project")