feat: implement re-authentication flow for Linear and Notion HITL connectors and improve their HITL flow and error states

- Added re-authentication endpoints for Linear and Notion connectors to handle expired authentication.
- Enhanced error handling in issue creation, deletion, and update tools to return appropriate authentication error messages.
- Updated UI components to display authentication status and guide users on re-authentication steps.
- Improved account health checks to ensure valid tokens are used for operations.
This commit is contained in:
Anish Sarkar 2026-03-18 14:10:11 +05:30
parent 5fb33b7cff
commit df872e261e
18 changed files with 724 additions and 155 deletions

View file

@ -1,9 +1,11 @@
import logging
from dataclasses import dataclass
from sqlalchemy import and_, func
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy.future import select
from app.connectors.notion_history import NotionHistoryConnector
from app.db import (
Document,
DocumentType,
@ -11,6 +13,8 @@ from app.db import (
SearchSourceConnectorType,
)
logger = logging.getLogger(__name__)
@dataclass
class NotionAccount:
@ -83,8 +87,15 @@ class NotionToolMetadataService:
search_space_id, accounts
)
accounts_with_status = []
for acc in accounts:
acc_dict = acc.to_dict()
auth_expired = await self._check_account_health(acc.id)
acc_dict["auth_expired"] = auth_expired
accounts_with_status.append(acc_dict)
return {
"accounts": [acc.to_dict() for acc in accounts],
"accounts": accounts_with_status,
"parent_pages": parent_pages,
}
@ -109,8 +120,8 @@ class NotionToolMetadataService:
if not document:
return {
"error": f"Page '{page_title}' not found in your indexed Notion pages. "
"This could mean: (1) the page doesn't exist, (2) it hasn't been indexed yet, "
"error": f"Page '{page_title}' not found in your synced Notion pages. "
"This could mean: (1) the page doesn't exist, (2) it hasn't been synced yet, "
"or (3) the page title is different. Please check the exact page title in Notion."
}
@ -167,6 +178,26 @@ class NotionToolMetadataService:
connectors = result.scalars().all()
return [NotionAccount.from_connector(conn) for conn in connectors]
async def _check_account_health(self, connector_id: int) -> bool:
"""Check if a Notion connector's token is still valid.
Uses a lightweight ``users.me()`` call to verify the token.
Returns True if the token is expired/invalid, False if healthy.
"""
try:
connector = NotionHistoryConnector(
session=self._db_session, connector_id=connector_id
)
client = await connector._get_client()
await client.users.me()
return False
except Exception as e:
logger.warning(
"Notion connector %s health check failed: %s", connector_id, e
)
return True
async def _get_parent_pages_by_account(
self, search_space_id: int, accounts: list[NotionAccount]
) -> dict: