feat: add Linear org name fetch and update route

This commit is contained in:
CREDO23 2026-01-07 08:16:04 +02:00
parent 932222bff1
commit d03b8dae34
3 changed files with 73 additions and 8 deletions

View file

@ -592,3 +592,4 @@ class LinearConnector:
return dt.strftime("%Y-%m-%d %H:%M:%S")
except ValueError:
return iso_date

View file

@ -0,0 +1,60 @@
"""
Linear OAuth Utilities.
Provides functions for fetching user/organization info from Linear API.
Separated from linear_connector.py to avoid circular imports.
"""
import logging
import httpx
logger = logging.getLogger(__name__)
LINEAR_GRAPHQL_URL = "https://api.linear.app/graphql"
ORGANIZATION_QUERY = """
query {
organization {
name
}
}
"""
async def fetch_linear_organization_name(access_token: str) -> str | None:
"""
Fetch organization/workspace name from Linear GraphQL API.
Args:
access_token: The Linear OAuth access token
Returns:
Organization name or None if fetch fails
"""
try:
async with httpx.AsyncClient() as client:
response = await client.post(
LINEAR_GRAPHQL_URL,
headers={
"Authorization": access_token,
"Content-Type": "application/json",
},
json={"query": ORGANIZATION_QUERY},
timeout=10.0,
)
if response.status_code == 200:
data = response.json()
org_name = data.get("data", {}).get("organization", {}).get("name")
if org_name:
logger.debug(f"Fetched Linear organization name: {org_name}")
return org_name
logger.warning(f"Failed to fetch Linear org info: {response.status_code}")
return None
except Exception as e:
logger.warning(f"Error fetching Linear organization name: {e!s}")
return None

View file

@ -23,10 +23,11 @@ from app.db import (
User,
get_async_session,
)
from app.connectors.linear_oauth import fetch_linear_organization_name
from app.schemas.linear_auth_credentials import LinearAuthCredentialsBase
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.connector_naming import generate_unique_connector_name, extract_identifier_from_credentials
logger = logging.getLogger(__name__)
@ -241,6 +242,9 @@ async def linear_callback(
status_code=400, detail="No access token received from Linear"
)
# Fetch organization name before encrypting credentials
org_name = await fetch_linear_organization_name(access_token)
# Calculate expiration time (UTC, tz-aware)
expires_at = None
if token_json.get("expires_in"):
@ -261,13 +265,13 @@ async def linear_callback(
"_token_encrypted": True,
}
# Extract unique identifier from connector credentials
connector_identifier = extract_identifier_from_credentials(
SearchSourceConnectorType.LINEAR_CONNECTOR, connector_config
)
# Generate a unique, user-friendly connector name from credentials/account info
connector_name = generate_unique_connector_name(
SearchSourceConnectorType.LINEAR_CONNECTOR, connector_identifier
# Generate a unique, user-friendly connector name
connector_name = await generate_unique_connector_name(
session,
SearchSourceConnectorType.LINEAR_CONNECTOR,
space_id,
user_id,
org_name,
)
# Create new connector
new_connector = SearchSourceConnector(