142 lines
5.7 KiB
Python
142 lines
5.7 KiB
Python
import time
|
|
import datetime
|
|
import requests
|
|
from flask import current_app
|
|
|
|
class WebexManager:
|
|
def __init__(self, db_collection, client_id, client_secret, redirect_uri, team_id, user_id):
|
|
self.db = db_collection
|
|
self.client_id = client_id
|
|
self.client_secret = client_secret
|
|
self.redirect_uri = redirect_uri
|
|
self.team_id = team_id
|
|
self.user_id = user_id
|
|
self.base_url = "https://webexapis.com/v1"
|
|
|
|
def save_tokens(self, token_data: dict):
|
|
"""Saves or updates Webex OAuth tokens in MongoDB."""
|
|
now = time.time()
|
|
doc = {
|
|
"_id": "webex_credentials",
|
|
"access_token": token_data.get("access_token"),
|
|
"refresh_token": token_data.get("refresh_token"),
|
|
"expires_at": now + token_data.get("expires_in", 43200) - 300, # Subtract 5 mins buffer
|
|
"refresh_token_expires_at": now + token_data.get("refresh_token_expires_in", 7776000),
|
|
"updated_at": datetime.datetime.now(datetime.timezone.utc).isoformat()
|
|
}
|
|
self.db.replace_one({"_id": "webex_credentials"}, doc, upsert=True)
|
|
return doc
|
|
|
|
def get_access_token(self) -> str:
|
|
"""Retrieves a valid access token from MongoDB, auto-refreshing if expired."""
|
|
token_doc = self.db.find_one({"_id": "webex_credentials"})
|
|
if not token_doc:
|
|
raise Exception("No Webex OAuth tokens found. Please complete login at /oauth/login.")
|
|
|
|
# Check if access token is expired
|
|
if time.time() >= token_doc.get("expires_at", 0):
|
|
current_app.logger.info("Webex access token expired. Refreshing...")
|
|
return self.refresh_token(token_doc.get("refresh_token"))
|
|
|
|
return token_doc.get("access_token")
|
|
|
|
def exchange_code(self, code: str) -> dict:
|
|
"""Exchanges OAuth code for access and refresh tokens."""
|
|
payload = {
|
|
"grant_type": "authorization_code",
|
|
"client_id": self.client_id,
|
|
"client_secret": self.client_secret,
|
|
"code": code,
|
|
"redirect_uri": self.redirect_uri
|
|
}
|
|
res = requests.post(f"{self.base_url}/access_token", data=payload)
|
|
res.raise_for_status()
|
|
return self.save_tokens(res.json())
|
|
|
|
def refresh_token(self, refresh_token: str) -> str:
|
|
"""Refreshes the Webex access token using the stored refresh_token."""
|
|
payload = {
|
|
"grant_type": "refresh_token",
|
|
"client_id": self.client_id,
|
|
"client_secret": self.client_secret,
|
|
"refresh_token": refresh_token
|
|
}
|
|
res = requests.post(f"{self.base_url}/access_token", data=payload)
|
|
res.raise_for_status()
|
|
new_doc = self.save_tokens(res.json())
|
|
return new_doc["access_token"]
|
|
|
|
def create_support_room(self, client_name: str, client_email: str, alert_type: str, alert_message: str, alert_id: str) -> str:
|
|
"""Creates a team support room and invites the client and yourself."""
|
|
access_token = self.get_access_token()
|
|
headers = {
|
|
"Authorization": f"Bearer {access_token}",
|
|
"Content-Type": "application/json"
|
|
}
|
|
|
|
# 1. Create room under team
|
|
room_res = requests.post(
|
|
f"{self.base_url}/rooms",
|
|
headers=headers,
|
|
json={
|
|
"title": f"Smartwave Support: {client_name} - {alert_type} ({alert_id})",
|
|
"teamId": self.team_id
|
|
}
|
|
)
|
|
room_res.raise_for_status()
|
|
room_details = room_res.json()
|
|
room_id = room_details["id"]
|
|
|
|
# 2. Add Client via email (Webex sends invite if user does not exist)
|
|
if client_email:
|
|
requests.post(
|
|
f"{self.base_url}/memberships",
|
|
headers=headers,
|
|
json={"roomId": room_id, "personEmail": client_email}
|
|
)
|
|
|
|
# 3. Add yourself (WEBEX_NINLUC_ID)
|
|
if self.user_id:
|
|
requests.post(
|
|
f"{self.base_url}/memberships",
|
|
headers=headers,
|
|
json={"roomId": room_id, "personId": self.user_id}
|
|
)
|
|
|
|
# 4. Optional: Send initial welcome message in the room
|
|
self.send_message(
|
|
room_id,
|
|
message=f"Support room initialized for {client_name}. An agent will be with you shortly.",
|
|
access_token=access_token
|
|
)
|
|
self.send_alert_info_message(room_id, alert_type, alert_message, alert_id, access_token=access_token)
|
|
|
|
return room_details
|
|
|
|
def send_message(self, room_id: str, message: str | None = None, markdown: str | None = None, access_token: str | None = None):
|
|
# Fetch the token so it auto-refreshes if needed
|
|
if not access_token:
|
|
access_token = self.get_access_token()
|
|
headers = {
|
|
"Authorization": f"Bearer {access_token}",
|
|
"Content-Type": "application/json"
|
|
}
|
|
|
|
requests.post(
|
|
f"{self.base_url}/messages",
|
|
headers=headers,
|
|
json={
|
|
"roomId": room_id,
|
|
"text": message,
|
|
"markdown": markdown
|
|
}
|
|
).raise_for_status()
|
|
|
|
def send_alert_info_message(self, room_id: str, alert_type: str, alert_message: str, alert_id: str, added_alert_info: bool = False, access_token: str | None = None):
|
|
"""Sends a structured alert info message to the specified Webex room."""
|
|
if added_alert_info:
|
|
message = f"Additional Alert Details:\n- Type: {alert_type}\n- Message: {alert_message}\n- Alert ID: {alert_id}"
|
|
else:
|
|
message = f"Alert Details:\n- Type: {alert_type}\n- Message: {alert_message}\n- Alert ID: {alert_id}"
|
|
|
|
self.send_message(room_id, message=message, access_token=access_token) |