Skip to content

Commit

Permalink
feat(backend): send org approval message to creator (#2008)
Browse files Browse the repository at this point in the history
* feat: approval notification for organisation approval in the background

* feat(osm): enhance message sending by allowing recipient username or ID
  • Loading branch information
Anuj-Gupta4 authored Dec 20, 2024
1 parent a79edb1 commit 7f012c6
Show file tree
Hide file tree
Showing 5 changed files with 105 additions and 3 deletions.
1 change: 0 additions & 1 deletion src/backend/app/auth/auth_deps.py
Original file line number Diff line number Diff line change
Expand Up @@ -273,7 +273,6 @@ async def login_required(
request,
settings.cookie_name, # FMTM cookie
)
print("manage")
return await _authenticate_user(extracted_token)


Expand Down
50 changes: 50 additions & 0 deletions src/backend/app/auth/providers/osm.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,9 @@
import os
from time import time

import requests
from fastapi import Request, Response
from fastapi.exceptions import HTTPException
from loguru import logger as log
from osm_login_python.core import Auth

Expand Down Expand Up @@ -107,3 +109,51 @@ async def handle_osm_callback(request: Request, osm_auth: Auth):
)

return response_plus_cookies


def get_osm_token(request: Request, osm_auth: Auth) -> str:
"""Extract and deserialize OSM token from cookies."""
cookie_name = f"{settings.cookie_name}_osm"
log.debug(f"Extracting OSM token from cookie {cookie_name}")
serialised_osm_token = request.cookies.get(cookie_name)
if not serialised_osm_token:
raise HTTPException(
status_code=HTTPStatus.UNAUTHORIZED,
detail="You must be logged in to your OpenStreetMap account.",
)
return osm_auth.deserialize_data(serialised_osm_token)


def send_osm_message(
osm_token: str,
title: str,
body: str,
osm_username: str = None,
osm_id: int = None,
) -> None:
"""Send a message via OSM API."""
if not osm_username and not osm_id:
raise ValueError("Either recipient or recipient_id must be provided.")

email_url = f"{settings.OSM_URL}api/0.6/user/messages"
headers = {"Authorization": f"Bearer {osm_token}"}
post_body = {
"title": title,
"body": body,
}

if osm_id:
post_body["recipient_id"] = osm_id
else:
post_body["recipient"] = osm_username

log.debug(
f"Sending message to user ({osm_id or osm_username}) via OSM API: {email_url}"
)
response = requests.post(email_url, headers=headers, data=post_body)

if response.status_code == 200:
log.info("Message sent successfully")
else:
msg = "Sending message via OSM failed"
log.error(f"{msg}: {response.text}")
1 change: 1 addition & 0 deletions src/backend/app/helpers/helper_routes.py
Original file line number Diff line number Diff line change
Expand Up @@ -313,6 +313,7 @@ async def send_test_osm_message(
> Notes section
""")
# NOTE post body should contain either recipient or recipient_id
post_body = {
"recipient_id": 16289154,
# "recipient_id": current_user.id,
Expand Down
37 changes: 36 additions & 1 deletion src/backend/app/organisations/organisation_crud.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,19 @@
#
"""Logic for organisation management."""

from fastapi import UploadFile
from textwrap import dedent

from fastapi import (
Request,
UploadFile,
)
from loguru import logger as log
from osm_login_python.core import Auth
from psycopg import Connection
from psycopg.rows import class_row

from app.auth.auth_schemas import AuthUser
from app.auth.providers.osm import get_osm_token, send_osm_message
from app.config import settings
from app.db.enums import MappingLevel, UserRole
from app.db.models import DbOrganisation, DbOrganisationManagers, DbUser
Expand Down Expand Up @@ -118,3 +126,30 @@ async def get_my_organisations(
async with db.cursor(row_factory=class_row(OrganisationOut)) as cur:
await cur.execute(sql, {"user_id": current_user.id})
return await cur.fetchall()


async def send_approval_message(
request: Request,
creator_id: int,
organisation_name: str,
osm_auth: Auth,
):
"""Send message to the organisation creator after approval."""
log.info(f"Sending approval message to organisation creator ({creator_id}).")
osm_token = get_osm_token(request, osm_auth)
message_content = dedent(f"""
## Congratulations!
Your organisation **{organisation_name}** has been approved.
You can now manage your organisation freely.
Thank you for being a part of our platform!
""")
send_osm_message(
osm_token=osm_token,
osm_id=creator_id,
title="Your organisation has been approved!",
body=message_content,
)
log.info(f"Approval message sent to organisation creator ({creator_id}).")
19 changes: 18 additions & 1 deletion src/backend/app/organisations/organisation_routes.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,11 @@

from fastapi import (
APIRouter,
BackgroundTasks,
Depends,
File,
HTTPException,
Request,
Response,
UploadFile,
)
Expand All @@ -32,6 +34,7 @@

from app.auth.auth_deps import login_required
from app.auth.auth_schemas import AuthUser, OrgUserDict
from app.auth.providers.osm import init_osm_auth
from app.auth.roles import org_admin, super_admin
from app.db.database import db_conn
from app.db.enums import HTTPStatus
Expand Down Expand Up @@ -128,13 +131,18 @@ async def delete_unapproved_org(

@router.post("/approve", response_model=OrganisationOut)
async def approve_organisation(
request: Request,
org_id: int,
background_tasks: BackgroundTasks,
db: Annotated[Connection, Depends(db_conn)],
current_user: Annotated[AuthUser, Depends(super_admin)],
osm_auth=Depends(init_osm_auth),
):
"""Approve the organisation request made by the user.
The logged in user must be super admin to perform this action .
The logged in user must be super admin to perform this action.
A background task notifies the organisation creator.
"""
log.info(f"Approving organisation ({org_id}).")
approved_org = await DbOrganisation.update(
Expand All @@ -148,6 +156,15 @@ async def approve_organisation(
db, approved_org.id, approved_org.created_by
)

log.info(f"Approved organisation ({org_id}).")
background_tasks.add_task(
organisation_crud.send_approval_message,
request=request,
creator_id=approved_org.created_by,
organisation_name=approved_org.name,
osm_auth=osm_auth,
)

return approved_org


Expand Down

0 comments on commit 7f012c6

Please sign in to comment.