Skip to content

Commit b15bba4

Browse files
committed
fix scopes issues for google services
1 parent 68030b4 commit b15bba4

2 files changed

Lines changed: 222 additions & 61 deletions

File tree

surfsense_backend/app/routes/search_source_connectors_routes.py

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
index_discord_messages,
4242
index_github_repos,
4343
index_google_calendar_events,
44+
index_google_gmail_messages,
4445
index_jira_issues,
4546
index_linear_issues,
4647
index_notion_pages,
@@ -507,6 +508,22 @@ async def index_connector_content(
507508
indexing_to,
508509
)
509510
response_message = "Google Calendar indexing started in the background."
511+
elif (
512+
connector.connector_type == SearchSourceConnectorType.GOOGLE_GMAIL_CONNECTOR
513+
):
514+
# Run indexing in background
515+
logger.info(
516+
f"Triggering Google Gmail indexing for connector {connector_id} into search space {search_space_id} from {indexing_from} to {indexing_to}"
517+
)
518+
background_tasks.add_task(
519+
run_google_gmail_indexing_with_new_session,
520+
connector_id,
521+
search_space_id,
522+
str(user.id),
523+
indexing_from,
524+
indexing_to,
525+
)
526+
response_message = "Google Gmail indexing started in the background."
510527

511528
elif connector.connector_type == SearchSourceConnectorType.DISCORD_CONNECTOR:
512529
# Run indexing in background
@@ -1113,3 +1130,62 @@ async def run_google_calendar_indexing(
11131130
exc_info=True,
11141131
)
11151132
# Optionally update status in DB to indicate failure
1133+
1134+
1135+
async def run_google_gmail_indexing_with_new_session(
1136+
connector_id: int,
1137+
search_space_id: int,
1138+
user_id: str,
1139+
max_messages: int,
1140+
days_back: int,
1141+
):
1142+
"""Wrapper to run Google Gmail indexing with its own database session."""
1143+
logger.info(
1144+
f"Background task started: Indexing Google Gmail connector {connector_id} into space {search_space_id} for {max_messages} messages from the last {days_back} days"
1145+
)
1146+
async with async_session_maker() as session:
1147+
await run_google_gmail_indexing(
1148+
session, connector_id, search_space_id, user_id, max_messages, days_back
1149+
)
1150+
logger.info(
1151+
f"Background task finished: Indexing Google Gmail connector {connector_id}"
1152+
)
1153+
1154+
1155+
async def run_google_gmail_indexing(
1156+
session: AsyncSession,
1157+
connector_id: int,
1158+
search_space_id: int,
1159+
user_id: str,
1160+
max_messages: int,
1161+
days_back: int,
1162+
):
1163+
"""Runs the Google Gmail indexing task and updates the timestamp."""
1164+
try:
1165+
indexed_count, error_message = await index_google_gmail_messages(
1166+
session,
1167+
connector_id,
1168+
search_space_id,
1169+
user_id,
1170+
max_messages,
1171+
days_back,
1172+
update_last_indexed=False,
1173+
)
1174+
if error_message:
1175+
logger.error(
1176+
f"Google Gmail indexing failed for connector {connector_id}: {error_message}"
1177+
)
1178+
# Optionally update status in DB to indicate failure
1179+
else:
1180+
logger.info(
1181+
f"Google Gmail indexing successful for connector {connector_id}. Indexed {indexed_count} documents."
1182+
)
1183+
# Update the last indexed timestamp only on success
1184+
await update_connector_last_indexed(session, connector_id)
1185+
await session.commit() # Commit timestamp update
1186+
except Exception as e:
1187+
logger.error(
1188+
f"Critical error in run_google_gmail_indexing for connector {connector_id}: {e}",
1189+
exc_info=True,
1190+
)
1191+
# Optionally update status in DB to indicate failure

surfsense_backend/app/tasks/connectors_indexing_tasks.py

Lines changed: 146 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -3381,8 +3381,10 @@ async def index_google_gmail_messages(
33813381
connector_id: int,
33823382
search_space_id: int,
33833383
user_id: str,
3384+
start_date: str | None = None,
3385+
end_date: str | None = None,
3386+
update_last_indexed: bool = True,
33843387
max_messages: int = 100,
3385-
days_back: int = 30,
33863388
) -> tuple[int, str]:
33873389
"""
33883390
Index Gmail messages for a specific connector.
@@ -3392,14 +3394,24 @@ async def index_google_gmail_messages(
33923394
connector_id: ID of the Gmail connector
33933395
search_space_id: ID of the search space
33943396
user_id: ID of the user
3397+
start_date: Start date for filtering messages (YYYY-MM-DD format)
3398+
end_date: End date for filtering messages (YYYY-MM-DD format)
3399+
update_last_indexed: Whether to update the last_indexed_at timestamp (default: True)
33953400
max_messages: Maximum number of messages to fetch (default: 100)
3396-
days_back: Number of days to look back (default: 30)
33973401
33983402
Returns:
33993403
Tuple of (number_of_indexed_messages, status_message)
34003404
"""
34013405
task_logger = TaskLoggingService(session, search_space_id)
34023406

3407+
# Calculate days back based on start_date
3408+
if start_date:
3409+
try:
3410+
start_date_obj = datetime.strptime(start_date, "%Y-%m-%d")
3411+
days_back = (datetime.now() - start_date_obj).days
3412+
except ValueError:
3413+
days_back = 30 # Default to 30 days if start_date is invalid
3414+
34033415
# Log task start
34043416
log_entry = await task_logger.log_task_start(
34053417
task_name="google_gmail_messages_indexing",
@@ -3426,8 +3438,8 @@ async def index_google_gmail_messages(
34263438

34273439
if not connector:
34283440
error_msg = f"Gmail connector with ID {connector_id} not found"
3429-
await task_logger.log_task_completion(
3430-
log_entry.id, "FAILED", error_msg, {"error_type": "ConnectorNotFound"}
3441+
await task_logger.log_task_failure(
3442+
log_entry, error_msg, {"error_type": "ConnectorNotFound"}
34313443
)
34323444
return 0, error_msg
34333445

@@ -3442,31 +3454,53 @@ async def index_google_gmail_messages(
34423454
scopes=config_data.get("scopes", []),
34433455
)
34443456

3445-
# Initialize Gmail connector
3457+
if (
3458+
not credentials.client_id
3459+
or not credentials.client_secret
3460+
or not credentials.refresh_token
3461+
):
3462+
await task_logger.log_task_failure(
3463+
log_entry,
3464+
f"Google gmail credentials not found in connector config for connector {connector_id}",
3465+
"Missing Google gmail credentials",
3466+
{"error_type": "MissingCredentials"},
3467+
)
3468+
return 0, "Google gmail credentials not found in connector config"
3469+
3470+
# Initialize Google gmail client
3471+
await task_logger.log_task_progress(
3472+
log_entry,
3473+
f"Initializing Google gmail client for connector {connector_id}",
3474+
{"stage": "client_initialization"},
3475+
)
3476+
3477+
# Initialize Google gmail connector
34463478
gmail_connector = GoogleGmailConnector(credentials)
34473479

3448-
# Fetch recent messages
3449-
logger.info(f"Fetching recent Gmail messages for connector {connector_id}")
3480+
# Fetch recent Google gmail messages
3481+
logger.info(f"Fetching recent emails for connector {connector_id}")
34503482
messages, error = gmail_connector.get_recent_messages(
34513483
max_results=max_messages, days_back=days_back
34523484
)
34533485

34543486
if error:
3455-
await task_logger.log_task_completion(
3456-
log_entry.id, "FAILED", f"Failed to fetch messages: {error}", {}
3487+
await task_logger.log_task_failure(
3488+
log_entry, f"Failed to fetch messages: {error}", {}
34573489
)
34583490
return 0, f"Failed to fetch Gmail messages: {error}"
34593491

34603492
if not messages:
3461-
success_msg = "No Gmail messages found in the specified date range"
3462-
await task_logger.log_task_completion(
3463-
log_entry.id, "SUCCESS", success_msg, {"messages_count": 0}
3493+
success_msg = "No Google gmail messages found in the specified date range"
3494+
await task_logger.log_task_success(
3495+
log_entry, success_msg, {"messages_count": 0}
34643496
)
34653497
return 0, success_msg
34663498

3467-
logger.info(f"Found {len(messages)} Gmail messages to index")
3499+
logger.info(f"Found {len(messages)} Google gmail messages to index")
34683500

3469-
indexed_count = 0
3501+
documents_indexed = 0
3502+
skipped_messages = []
3503+
documents_skipped = 0
34703504
for message in messages:
34713505
try:
34723506
# Extract message information
@@ -3491,22 +3525,57 @@ async def index_google_gmail_messages(
34913525
elif name == "date":
34923526
date_str = value
34933527

3528+
if not message_id:
3529+
logger.warning(f"Skipping message with missing ID: {subject}")
3530+
skipped_messages.append(f"{subject} (missing ID)")
3531+
documents_skipped += 1
3532+
continue
3533+
3534+
# Format message to markdown
3535+
markdown_content = gmail_connector.format_message_to_markdown(message)
3536+
3537+
if not markdown_content.strip():
3538+
logger.warning(f"Skipping message with no content: {subject}")
3539+
skipped_messages.append(f"{subject} (no content)")
3540+
documents_skipped += 1
3541+
continue
3542+
3543+
# Create a simple summary
3544+
summary_content = f"Google Gmail Message: {subject}\n\n"
3545+
summary_content += f"Sender: {sender}\n"
3546+
summary_content += f"Date: {date_str}\n"
3547+
3548+
# Generate content hash
3549+
content_hash = generate_content_hash(markdown_content, search_space_id)
3550+
34943551
# Check if document already exists
3495-
existing_doc_result = await session.execute(
3496-
select(Document).filter(
3497-
Document.search_space_id == search_space_id,
3498-
Document.document_type == DocumentType.GOOGLE_GMAIL_CONNECTOR,
3499-
Document.document_metadata["message_id"].astext == message_id,
3500-
)
3552+
existing_doc_by_hash_result = await session.execute(
3553+
select(Document).where(Document.content_hash == content_hash)
3554+
)
3555+
existing_document_by_hash = (
3556+
existing_doc_by_hash_result.scalars().first()
35013557
)
3502-
existing_doc = existing_doc_result.scalars().first()
35033558

3504-
if existing_doc:
3505-
logger.info(f"Gmail message {message_id} already indexed, skipping")
3559+
if existing_document_by_hash:
3560+
logger.info(
3561+
f"Document with content hash {content_hash} already exists for message {message_id}. Skipping processing."
3562+
)
3563+
documents_skipped += 1
35063564
continue
35073565

3508-
# Format message to markdown
3509-
markdown_content = gmail_connector.format_message_to_markdown(message)
3566+
# Generate embedding for the summary
3567+
summary_embedding = config.embedding_model_instance.embed(
3568+
summary_content
3569+
)
3570+
3571+
# Process chunks
3572+
chunks = [
3573+
Chunk(
3574+
content=chunk.text,
3575+
embedding=config.embedding_model_instance.embed(chunk.text),
3576+
)
3577+
for chunk in config.chunker_instance.chunk(markdown_content)
3578+
]
35103579

35113580
# Create and store new document
35123581
logger.info(f"Creating new document for Gmail message: {subject}")
@@ -3523,56 +3592,72 @@ async def index_google_gmail_messages(
35233592
"connector_id": connector_id,
35243593
},
35253594
content=markdown_content,
3595+
content_hash=content_hash,
3596+
embedding=summary_embedding,
3597+
chunks=chunks,
35263598
)
35273599
session.add(document)
3528-
await session.flush()
3529-
3530-
# Create chunks for the document
3531-
chunks = config.chunker_instance.chunk(markdown_content)
3532-
for i, chunk_text in enumerate(chunks):
3533-
chunk = Chunk(
3534-
document_id=document.id,
3535-
content=chunk_text,
3536-
chunk_index=i,
3537-
embedding=config.embedding_model_instance.embed_query(
3538-
chunk_text
3539-
),
3540-
)
3541-
session.add(chunk)
3542-
3543-
indexed_count += 1
3544-
logger.info(f"Successfully indexed Gmail message: {subject}")
3600+
documents_indexed += 1
3601+
logger.info(f"Successfully indexed new email {summary_content}")
35453602

35463603
except Exception as e:
35473604
logger.error(
3548-
f"Error indexing Gmail message {message_id}: {e!s}", exc_info=True
3605+
f"Error processing the email {message_id}: {e!s}",
3606+
exc_info=True,
35493607
)
3550-
continue
3608+
skipped_messages.append(f"{subject} (processing error)")
3609+
documents_skipped += 1
3610+
continue # Skip this message and continue with others
3611+
3612+
# Update the last_indexed_at timestamp for the connector only if requested
3613+
total_processed = documents_indexed
3614+
if update_last_indexed:
3615+
connector.last_indexed_at = datetime.now()
3616+
logger.info(f"Updated last_indexed_at to {connector.last_indexed_at}")
35513617

35523618
# Commit all changes
35533619
await session.commit()
3620+
logger.info(
3621+
"Successfully committed all Google gmail document changes to database"
3622+
)
35543623

3555-
# Update connector's last_indexed_at timestamp
3556-
connector.last_indexed_at = datetime.now(UTC)
3557-
await session.commit()
3624+
# Log success
3625+
await task_logger.log_task_success(
3626+
log_entry,
3627+
f"Successfully completed Google gmail indexing for connector {connector_id}",
3628+
{
3629+
"events_processed": total_processed,
3630+
"documents_indexed": documents_indexed,
3631+
"documents_skipped": documents_skipped,
3632+
"skipped_messages_count": len(skipped_messages),
3633+
},
3634+
)
35583635

3559-
success_msg = f"Successfully indexed {indexed_count} Gmail messages"
3560-
await task_logger.log_task_completion(
3561-
log_entry.id,
3562-
"SUCCESS",
3563-
success_msg,
3564-
{"indexed_count": indexed_count, "total_messages": len(messages)},
3636+
logger.info(
3637+
f"Google gmail indexing completed: {documents_indexed} new emails, {documents_skipped} skipped"
35653638
)
3566-
logger.info(success_msg)
3567-
return indexed_count, success_msg
3639+
return (
3640+
total_processed,
3641+
None,
3642+
) # Return None as the error message to indicate success
35683643

3644+
except SQLAlchemyError as db_error:
3645+
await session.rollback()
3646+
await task_logger.log_task_failure(
3647+
log_entry,
3648+
f"Database error during Google gmail indexing for connector {connector_id}",
3649+
str(db_error),
3650+
{"error_type": "SQLAlchemyError"},
3651+
)
3652+
logger.error(f"Database error: {db_error!s}", exc_info=True)
3653+
return 0, f"Database error: {db_error!s}"
35693654
except Exception as e:
3570-
await task_logger.log_task_completion(
3571-
log_entry.id,
3572-
"FAILED",
3573-
f"Failed to index Gmail messages for connector {connector_id}",
3655+
await session.rollback()
3656+
await task_logger.log_task_failure(
3657+
log_entry,
3658+
f"Failed to index Google gmail emails for connector {connector_id}",
35743659
str(e),
35753660
{"error_type": type(e).__name__},
35763661
)
3577-
logger.error(f"Failed to index Gmail messages: {e!s}", exc_info=True)
3578-
return 0, f"Failed to index Gmail messages: {e!s}"
3662+
logger.error(f"Failed to index Google gmail emails: {e!s}", exc_info=True)
3663+
return 0, f"Failed to index Google gmail emails: {e!s}"

0 commit comments

Comments
 (0)