diff --git a/src/backend/app/auth/providers/osm.py b/src/backend/app/auth/providers/osm.py index 7d860a6ab..8ee1ec125 100644 --- a/src/backend/app/auth/providers/osm.py +++ b/src/backend/app/auth/providers/osm.py @@ -157,3 +157,20 @@ def send_osm_message( else: msg = "Sending message via OSM failed" log.error(f"{msg}: {response.text}") + + +async def check_osm_user(osm_username: str): + """Check if the user is an OSM user based on their username.""" + osm_url = f"https://www.openstreetmap.org/user/{osm_username}/" + + user_exists = False + try: + response = requests.get(osm_url) + if response.status_code == 200: + user_exists = True + except Exception as e: + log.exception( + f"Failed to check if user exists on OSM. Error: {e}", + stack_info=True, + ) + return user_exists diff --git a/src/backend/app/projects/project_crud.py b/src/backend/app/projects/project_crud.py index 7bb316303..cc24d6fdc 100644 --- a/src/backend/app/projects/project_crud.py +++ b/src/backend/app/projects/project_crud.py @@ -967,3 +967,36 @@ async def send_project_manager_message( body=message_content, ) log.info(f"Message sent to new project manager ({new_manager.username}).") + + +async def send_invitation_message( + request: Request, + project: DbProject, + invitee_username: str, + osm_auth: Auth, +): + """Send an invitation message to a user to join a project.""" + log.info(f"Sending invitation message to osm user ({invitee_username}).") + + osm_token = get_osm_token(request, osm_auth) + + project_url = f"{settings.FMTM_DOMAIN}/project/{project.id}" + if not project_url.startswith("http"): + project_url = f"https://{project_url}" + + message_content = dedent(f""" + You have been invited to join the project **{project.name}**. + + Please click this link: + [Project]({project_url}) + + Thank you for being a part of our platform! + """) + + send_osm_message( + osm_token=osm_token, + osm_username=invitee_username, + title=f"You have been invited to join the project {project.name}", + body=message_content, + ) + log.info(f"Invitation message sent to osm user ({invitee_username}).") diff --git a/src/backend/app/projects/project_routes.py b/src/backend/app/projects/project_routes.py index 4dcba3985..1c27420ae 100644 --- a/src/backend/app/projects/project_routes.py +++ b/src/backend/app/projects/project_routes.py @@ -48,7 +48,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 init_osm_auth +from app.auth.providers.osm import check_osm_user, init_osm_auth from app.auth.roles import mapper, org_admin, project_manager from app.central import central_crud, central_deps, central_schemas from app.config import settings @@ -759,6 +759,32 @@ async def add_new_project_manager( return Response(status_code=HTTPStatus.OK) +@router.post("/invite-new-user") +async def invite_new_user( + request: Request, + background_tasks: BackgroundTasks, + project: Annotated[DbProject, Depends(project_deps.get_project)], + invitee_username: str, + osm_auth=Depends(init_osm_auth), +): + """Invite a new user to a project.""" + user_exists = await check_osm_user(invitee_username) + + if not user_exists: + raise HTTPException( + status_code=HTTPStatus.NOT_FOUND, + detail="User does not exist on Open Street Map", + ) + background_tasks.add_task( + project_crud.send_invitation_message, + request=request, + project=project, + invitee_username=invitee_username, + osm_auth=osm_auth, + ) + return Response(status_code=HTTPStatus.OK) + + @router.post("/update-form") async def update_project_form( xlsform: Annotated[BytesIO, Depends(central_deps.read_xlsform)],