Files
Smartwave/cloud/APIs/webex.py
T
Ninluc 44b4c8034f
Build, push image, and notify Watchtower / build-image (push) Successful in 42s
Build, push image, and notify Watchtower / notify (push) Successful in 12s
better Webex
2026-08-17 14:46:35 +02:00

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)