# import json # import os # from typing import Type # from dotenv import load_dotenv # from langchain.pydantic_v1 import BaseModel, Field # from langchain_core.tools import BaseTool # from slack_sdk.errors import SlackApiError # from datetime import datetime # from google_auth_oauthlib.flow import InstalledAppFlow # from googleapiclient.discovery import build # from google.oauth2.credentials import Credentials # from google.auth.transport.requests import Request # from config import client # SCOPES = ['https://www.googleapis.com/auth/calendar'] # TOKEN_DIR = "token_files" # TOKEN_FILE = f"{TOKEN_DIR}/token.json" # def create_service(client_secret_file, api_name, api_version, user_id, *scopes): # """ # Create a Google API service instance using stored credentials for a given user. # Parameters: # - client_secret_file (str): Path to your client secrets JSON file. # - api_name (str): The Google API service name (e.g., 'calendar'). # - api_version (str): The API version (e.g., 'v3'). # - user_id (str): The unique identifier for the user (e.g., Slack user ID). # - scopes (tuple): A tuple/list of scopes. (Pass as: [SCOPES]) # Returns: # - service: The built Google API service instance, or None if authentication is required. # """ # scopes = list(scopes[0]) # Unpack scopes # creds = None # user_token_file = os.path.join(TOKEN_DIR, f"token.json") # if os.path.exists(user_token_file): # try: # creds = Credentials.from_authorized_user_file(user_token_file, scopes) # except ValueError as e: # print(f"Error loading credentials: {e}") # # os.remove(user_token_file) # creds = None # print(creds) # # If credentials are absent or invalid, we cannot proceed. # if not creds or not creds.valid: # if creds and creds.expired and creds.refresh_token: # try: # creds.refresh(Request()) # except Exception as e: # print(f"Error refreshing token: {e}") # return None # else: # print("No valid credentials available. Please re-authenticate.") # return None # # Save the refreshed token. # with open(user_token_file, 'w') as token_file: # token_file.write(creds.to_json()) # try: # service = build(api_name, api_version, credentials=creds, static_discovery=False) # return service # except Exception as e: # print(f"Failed to create service instance for {api_name}: {e}") # os.remove(user_token_file) # Remove the token file if it's causing issues. # return None # def construct_google_calendar_client(user_id): # """ # Constructs a Google Calendar API client for the specified user. # Parameters: # - user_id (str): The unique user identifier (e.g., Slack user ID). # Returns: # - service: The Google Calendar API service instance or None if not authenticated. # """ # API_NAME = 'calendar' # API_VERSION = 'v3' # return create_service('credentials.json', API_NAME, API_VERSION, user_id, SCOPES) import json import os from datetime import datetime import psycopg2 from dotenv import load_dotenv from google.oauth2.credentials import Credentials from google.auth.transport.requests import Request from googleapiclient.discovery import build # Load environment variables from a .env file load_dotenv() # Database helper functions def load_token(team_id, user_id, service): conn = psycopg2.connect(os.getenv('DATABASE_URL')) cur = conn.cursor() cur.execute('SELECT token_data FROM Tokens WHERE team_id = %s AND user_id = %s AND service = %s', (team_id, user_id, service)) row = cur.fetchone() cur.close() conn.close() print(f"DB ROW: {row[0]}") return json.loads(row[0]) if row else None def save_token(team_id, user_id, service, token_data): """ Save token data to the database for a specific team, user, and service. Parameters: team_id (str): The Slack team ID. user_id (str): The Slack user ID. service (str): The service name (e.g., 'google'). token_data (dict): The token data to save (e.g., {'access_token', 'refresh_token', 'expires_at'}). """ conn = psycopg2.connect(os.getenv('DATABASE_URL')) cur = conn.cursor() cur.execute( ''' INSERT INTO Tokens (team_id, user_id, service, token_data, updated_at) VALUES (%s, %s, %s, %s, %s) ON CONFLICT (team_id, user_id, service) DO UPDATE SET token_data = %s, updated_at = %s ''', ( team_id, user_id, service, json.dumps(token_data), datetime.now(), json.dumps(token_data), datetime.now() ) ) conn.commit() cur.close() conn.close() def create_service(team_id, user_id, api_name, api_version, scopes): """ Create a Google API service instance using stored credentials for a given user. Parameters: team_id (str): The Slack team ID. user_id (str): The Slack user ID. api_name (str): The Google API service name (e.g., 'calendar'). api_version (str): The API version (e.g., 'v3'). scopes (list): List of scopes required for the API. Returns: service: The built Google API service instance, or None if authentication fails. """ # Load token data from the database token_data = load_token(team_id, user_id, 'google') if not token_data: print(f"No token found for team {team_id}, user {user_id}. Initial authorization required.") return None # Fetch client credentials from environment variables client_id = os.getenv('GOOGLE_CLIENT_ID') client_secret = os.getenv('GOOGLE_CLIENT_SECRET') token_uri = os.getenv('GOOGLE_TOKEN_URI', 'https://oauth2.googleapis.com/token') if not client_id or not client_secret: print("Google client credentials not found in environment variables.") return None # Create Credentials object using token data and client credentials try: creds = Credentials( token=token_data.get('access_token'), refresh_token=token_data.get('refresh_token'), token_uri=token_uri, client_id=client_id, client_secret=client_secret, scopes=scopes ) except ValueError as e: print(f"Error creating credentials for user {user_id}: {e}") return None # Refresh token if expired if not creds.valid: if creds.expired and creds.refresh_token: try: creds.refresh(Request()) # Save refreshed token data to the database refreshed_token_data = { 'access_token': creds.token, 'refresh_token': creds.refresh_token, 'expires_at': creds.expiry.timestamp() if creds.expiry else None } save_token(team_id, user_id, 'google', refreshed_token_data) print(f"Token refreshed for user {user_id}.") except Exception as e: print(f"Error refreshing token for user {user_id}: {e}") return None else: print(f"Credentials invalid and no refresh token available for user {user_id}.") return None # Build and return the Google API service try: service = build(api_name, api_version, credentials=creds, static_discovery=False) return service except Exception as e: print(f"Failed to create service instance for {api_name}: {e}") return None def construct_google_calendar_client(team_id, user_id): """ Constructs a Google Calendar API client for the specified user. Parameters: team_id (str): The Slack team ID. user_id (str): The Slack user ID. Returns: service: The Google Calendar API service instance, or None if not authenticated. """ API_NAME = 'calendar' API_VERSION = 'v3' SCOPES = ['https://www.googleapis.com/auth/calendar'] return create_service(team_id, user_id, API_NAME, API_VERSION, SCOPES)