mirror of
https://github.com/MODSetter/SurfSense.git
synced 2026-06-08 20:25:19 +02:00
feat: add fetch_google_user_email and update Google OAuth routes
This commit is contained in:
parent
4c6a782cec
commit
932222bff1
4 changed files with 65 additions and 25 deletions
|
|
@ -6,6 +6,7 @@ Allows fetching emails from Gmail mailbox using Google OAuth credentials.
|
||||||
|
|
||||||
import base64
|
import base64
|
||||||
import json
|
import json
|
||||||
|
import logging
|
||||||
import re
|
import re
|
||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
|
|
@ -21,6 +22,34 @@ from app.db import (
|
||||||
SearchSourceConnectorType,
|
SearchSourceConnectorType,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
def fetch_google_user_email(credentials: Credentials) -> str | None:
|
||||||
|
"""
|
||||||
|
Fetch user email from Gmail API using Google credentials.
|
||||||
|
|
||||||
|
Uses the Gmail users.getProfile endpoint which returns the authenticated
|
||||||
|
user's email address.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
credentials: Google OAuth Credentials object (not encrypted)
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
User's email address or None if fetch fails
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
service = build("gmail", "v1", credentials=credentials)
|
||||||
|
profile = service.users().getProfile(userId="me").execute()
|
||||||
|
email = profile.get("emailAddress")
|
||||||
|
if email:
|
||||||
|
logger.debug(f"Fetched Google user email: {email}")
|
||||||
|
return email
|
||||||
|
return None
|
||||||
|
except Exception as e:
|
||||||
|
logger.warning(f"Error fetching Google user email: {e!s}")
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
class GoogleGmailConnector:
|
class GoogleGmailConnector:
|
||||||
"""Class for retrieving emails from Gmail using Google OAuth credentials."""
|
"""Class for retrieving emails from Gmail using Google OAuth credentials."""
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,7 @@ from sqlalchemy.ext.asyncio import AsyncSession
|
||||||
from sqlalchemy.future import select
|
from sqlalchemy.future import select
|
||||||
|
|
||||||
from app.config import config
|
from app.config import config
|
||||||
|
from app.connectors.google_gmail_connector import fetch_google_user_email
|
||||||
from app.db import (
|
from app.db import (
|
||||||
SearchSourceConnector,
|
SearchSourceConnector,
|
||||||
SearchSourceConnectorType,
|
SearchSourceConnectorType,
|
||||||
|
|
@ -22,8 +23,8 @@ from app.db import (
|
||||||
get_async_session,
|
get_async_session,
|
||||||
)
|
)
|
||||||
from app.users import current_active_user
|
from app.users import current_active_user
|
||||||
|
from app.utils.connector_naming import generate_unique_connector_name
|
||||||
from app.utils.oauth_security import OAuthStateManager, TokenEncryption
|
from app.utils.oauth_security import OAuthStateManager, TokenEncryption
|
||||||
from app.utils.connector_naming import generate_unique_connector_name, extract_identifier_from_credentials
|
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
@ -173,6 +174,9 @@ async def calendar_callback(
|
||||||
creds = flow.credentials
|
creds = flow.credentials
|
||||||
creds_dict = json.loads(creds.to_json())
|
creds_dict = json.loads(creds.to_json())
|
||||||
|
|
||||||
|
# Fetch user email before encrypting credentials
|
||||||
|
user_email = fetch_google_user_email(creds)
|
||||||
|
|
||||||
# Encrypt sensitive credentials before storing
|
# Encrypt sensitive credentials before storing
|
||||||
token_encryption = get_token_encryption()
|
token_encryption = get_token_encryption()
|
||||||
|
|
||||||
|
|
@ -192,14 +196,13 @@ async def calendar_callback(
|
||||||
creds_dict["_token_encrypted"] = True
|
creds_dict["_token_encrypted"] = True
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
# Generate a unique, user-friendly connector name
|
||||||
# Extract unique identifier from connector credentials
|
connector_name = await generate_unique_connector_name(
|
||||||
connector_identifier = extract_identifier_from_credentials(
|
session,
|
||||||
SearchSourceConnectorType.GOOGLE_CALENDAR_CONNECTOR, creds_dict
|
SearchSourceConnectorType.GOOGLE_CALENDAR_CONNECTOR,
|
||||||
)
|
space_id,
|
||||||
# Generate a unique, user-friendly connector name from credentials/account info
|
user_id,
|
||||||
connector_name = generate_unique_connector_name(
|
user_email,
|
||||||
SearchSourceConnectorType.GOOGLE_CALENDAR_CONNECTOR, connector_identifier
|
|
||||||
)
|
)
|
||||||
db_connector = SearchSourceConnector(
|
db_connector = SearchSourceConnector(
|
||||||
name=connector_name,
|
name=connector_name,
|
||||||
|
|
|
||||||
|
|
@ -29,6 +29,7 @@ from app.connectors.google_drive import (
|
||||||
get_start_page_token,
|
get_start_page_token,
|
||||||
list_folder_contents,
|
list_folder_contents,
|
||||||
)
|
)
|
||||||
|
from app.connectors.google_gmail_connector import fetch_google_user_email
|
||||||
from app.db import (
|
from app.db import (
|
||||||
SearchSourceConnector,
|
SearchSourceConnector,
|
||||||
SearchSourceConnectorType,
|
SearchSourceConnectorType,
|
||||||
|
|
@ -36,8 +37,8 @@ from app.db import (
|
||||||
get_async_session,
|
get_async_session,
|
||||||
)
|
)
|
||||||
from app.users import current_active_user
|
from app.users import current_active_user
|
||||||
|
from app.utils.connector_naming import generate_unique_connector_name
|
||||||
from app.utils.oauth_security import OAuthStateManager, TokenEncryption
|
from app.utils.oauth_security import OAuthStateManager, TokenEncryption
|
||||||
from app.utils.connector_naming import generate_unique_connector_name, extract_identifier_from_credentials
|
|
||||||
|
|
||||||
# Relax token scope validation for Google OAuth
|
# Relax token scope validation for Google OAuth
|
||||||
os.environ["OAUTHLIB_RELAX_TOKEN_SCOPE"] = "1"
|
os.environ["OAUTHLIB_RELAX_TOKEN_SCOPE"] = "1"
|
||||||
|
|
@ -228,6 +229,9 @@ async def drive_callback(
|
||||||
creds = flow.credentials
|
creds = flow.credentials
|
||||||
creds_dict = json.loads(creds.to_json())
|
creds_dict = json.loads(creds.to_json())
|
||||||
|
|
||||||
|
# Fetch user email before encrypting credentials
|
||||||
|
user_email = fetch_google_user_email(creds)
|
||||||
|
|
||||||
# Encrypt sensitive credentials before storing
|
# Encrypt sensitive credentials before storing
|
||||||
token_encryption = get_token_encryption()
|
token_encryption = get_token_encryption()
|
||||||
|
|
||||||
|
|
@ -246,13 +250,13 @@ async def drive_callback(
|
||||||
# Mark that credentials are encrypted for backward compatibility
|
# Mark that credentials are encrypted for backward compatibility
|
||||||
creds_dict["_token_encrypted"] = True
|
creds_dict["_token_encrypted"] = True
|
||||||
|
|
||||||
# Extract unique identifier from connector credentials
|
# Generate a unique, user-friendly connector name
|
||||||
connector_identifier = extract_identifier_from_credentials(
|
connector_name = await generate_unique_connector_name(
|
||||||
SearchSourceConnectorType.GOOGLE_DRIVE_CONNECTOR, creds_dict
|
session,
|
||||||
)
|
SearchSourceConnectorType.GOOGLE_DRIVE_CONNECTOR,
|
||||||
# Generate a unique, user-friendly connector name from credentials/account info
|
space_id,
|
||||||
connector_name = generate_unique_connector_name(
|
user_id,
|
||||||
SearchSourceConnectorType.GOOGLE_DRIVE_CONNECTOR, connector_identifier
|
user_email,
|
||||||
)
|
)
|
||||||
|
|
||||||
db_connector = SearchSourceConnector(
|
db_connector = SearchSourceConnector(
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,7 @@ from sqlalchemy.ext.asyncio import AsyncSession
|
||||||
from sqlalchemy.future import select
|
from sqlalchemy.future import select
|
||||||
|
|
||||||
from app.config import config
|
from app.config import config
|
||||||
|
from app.connectors.google_gmail_connector import fetch_google_user_email
|
||||||
from app.db import (
|
from app.db import (
|
||||||
SearchSourceConnector,
|
SearchSourceConnector,
|
||||||
SearchSourceConnectorType,
|
SearchSourceConnectorType,
|
||||||
|
|
@ -22,8 +23,8 @@ from app.db import (
|
||||||
get_async_session,
|
get_async_session,
|
||||||
)
|
)
|
||||||
from app.users import current_active_user
|
from app.users import current_active_user
|
||||||
|
from app.utils.connector_naming import generate_unique_connector_name
|
||||||
from app.utils.oauth_security import OAuthStateManager, TokenEncryption
|
from app.utils.oauth_security import OAuthStateManager, TokenEncryption
|
||||||
from app.utils.connector_naming import generate_unique_connector_name, extract_identifier_from_credentials
|
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
@ -204,6 +205,9 @@ async def gmail_callback(
|
||||||
creds = flow.credentials
|
creds = flow.credentials
|
||||||
creds_dict = json.loads(creds.to_json())
|
creds_dict = json.loads(creds.to_json())
|
||||||
|
|
||||||
|
# Fetch user email before encrypting credentials
|
||||||
|
user_email = fetch_google_user_email(creds)
|
||||||
|
|
||||||
# Encrypt sensitive credentials before storing
|
# Encrypt sensitive credentials before storing
|
||||||
token_encryption = get_token_encryption()
|
token_encryption = get_token_encryption()
|
||||||
|
|
||||||
|
|
@ -223,13 +227,13 @@ async def gmail_callback(
|
||||||
creds_dict["_token_encrypted"] = True
|
creds_dict["_token_encrypted"] = True
|
||||||
|
|
||||||
try:
|
try:
|
||||||
# Extract unique identifier from connector credentials
|
# Generate a unique, user-friendly connector name
|
||||||
connector_identifier = extract_identifier_from_credentials(
|
connector_name = await generate_unique_connector_name(
|
||||||
SearchSourceConnectorType.GOOGLE_GMAIL_CONNECTOR, creds_dict
|
session,
|
||||||
)
|
SearchSourceConnectorType.GOOGLE_GMAIL_CONNECTOR,
|
||||||
# Generate a unique, user-friendly connector name from credentials/account info
|
space_id,
|
||||||
connector_name = generate_unique_connector_name(
|
user_id,
|
||||||
SearchSourceConnectorType.GOOGLE_GMAIL_CONNECTOR, connector_identifier
|
user_email,
|
||||||
)
|
)
|
||||||
db_connector = SearchSourceConnector(
|
db_connector = SearchSourceConnector(
|
||||||
name=connector_name,
|
name=connector_name,
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue