Fix sync TUI freeze by completing auth before starting dashboard
This commit is contained in:
@@ -715,6 +715,24 @@ def sync(
|
|||||||
else:
|
else:
|
||||||
# Default: Launch interactive TUI dashboard
|
# Default: Launch interactive TUI dashboard
|
||||||
from .sync_dashboard import run_dashboard_sync
|
from .sync_dashboard import run_dashboard_sync
|
||||||
|
from src.services.microsoft_graph.auth import has_valid_cached_token
|
||||||
|
|
||||||
|
# Check if we need to authenticate before starting the TUI
|
||||||
|
# This prevents the TUI from appearing to freeze during device flow auth
|
||||||
|
if not demo:
|
||||||
|
scopes = [
|
||||||
|
"https://graph.microsoft.com/Calendars.Read",
|
||||||
|
"https://graph.microsoft.com/Mail.ReadWrite",
|
||||||
|
]
|
||||||
|
if not has_valid_cached_token(scopes):
|
||||||
|
click.echo("Authentication required. Please complete the login flow...")
|
||||||
|
try:
|
||||||
|
# This will trigger the device flow auth in the console
|
||||||
|
get_access_token(scopes)
|
||||||
|
click.echo("Authentication successful! Starting dashboard...")
|
||||||
|
except Exception as e:
|
||||||
|
click.echo(f"Authentication failed: {e}")
|
||||||
|
return
|
||||||
|
|
||||||
sync_config = {
|
sync_config = {
|
||||||
"org": org,
|
"org": org,
|
||||||
@@ -936,6 +954,27 @@ def status():
|
|||||||
def interactive(org, vdir, notify, dry_run, demo):
|
def interactive(org, vdir, notify, dry_run, demo):
|
||||||
"""Launch interactive TUI dashboard for sync operations."""
|
"""Launch interactive TUI dashboard for sync operations."""
|
||||||
from .sync_dashboard import run_dashboard_sync
|
from .sync_dashboard import run_dashboard_sync
|
||||||
|
from src.services.microsoft_graph.auth import (
|
||||||
|
has_valid_cached_token,
|
||||||
|
get_access_token,
|
||||||
|
)
|
||||||
|
|
||||||
|
# Check if we need to authenticate before starting the TUI
|
||||||
|
# This prevents the TUI from appearing to freeze during device flow auth
|
||||||
|
if not demo:
|
||||||
|
scopes = [
|
||||||
|
"https://graph.microsoft.com/Calendars.Read",
|
||||||
|
"https://graph.microsoft.com/Mail.ReadWrite",
|
||||||
|
]
|
||||||
|
if not has_valid_cached_token(scopes):
|
||||||
|
click.echo("Authentication required. Please complete the login flow...")
|
||||||
|
try:
|
||||||
|
# This will trigger the device flow auth in the console
|
||||||
|
get_access_token(scopes)
|
||||||
|
click.echo("Authentication successful! Starting dashboard...")
|
||||||
|
except Exception as e:
|
||||||
|
click.echo(f"Authentication failed: {e}")
|
||||||
|
return
|
||||||
|
|
||||||
sync_config = {
|
sync_config = {
|
||||||
"org": org,
|
"org": org,
|
||||||
|
|||||||
@@ -25,6 +25,49 @@ def ensure_directory_exists(path):
|
|||||||
os.makedirs(path)
|
os.makedirs(path)
|
||||||
|
|
||||||
|
|
||||||
|
def has_valid_cached_token(scopes=None):
|
||||||
|
"""
|
||||||
|
Check if we have a valid cached token (without triggering auth flow).
|
||||||
|
|
||||||
|
Args:
|
||||||
|
scopes: List of scopes to check. If None, uses default scopes.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
bool: True if a valid cached token exists, False otherwise.
|
||||||
|
"""
|
||||||
|
if scopes is None:
|
||||||
|
scopes = ["https://graph.microsoft.com/Mail.Read"]
|
||||||
|
|
||||||
|
client_id = os.getenv("AZURE_CLIENT_ID")
|
||||||
|
tenant_id = os.getenv("AZURE_TENANT_ID")
|
||||||
|
|
||||||
|
if not client_id or not tenant_id:
|
||||||
|
return False
|
||||||
|
|
||||||
|
cache = msal.SerializableTokenCache()
|
||||||
|
cache_file = "token_cache.bin"
|
||||||
|
|
||||||
|
if not os.path.exists(cache_file):
|
||||||
|
return False
|
||||||
|
|
||||||
|
try:
|
||||||
|
cache.deserialize(open(cache_file, "r").read())
|
||||||
|
authority = f"https://login.microsoftonline.com/{tenant_id}"
|
||||||
|
app = msal.PublicClientApplication(
|
||||||
|
client_id, authority=authority, token_cache=cache
|
||||||
|
)
|
||||||
|
accounts = app.get_accounts()
|
||||||
|
|
||||||
|
if not accounts:
|
||||||
|
return False
|
||||||
|
|
||||||
|
# Try silent auth - this will return None if token is expired
|
||||||
|
token_response = app.acquire_token_silent(scopes, account=accounts[0])
|
||||||
|
return token_response is not None and "access_token" in token_response
|
||||||
|
except Exception:
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
def get_access_token(scopes):
|
def get_access_token(scopes):
|
||||||
"""
|
"""
|
||||||
Authenticate with Microsoft Graph API and obtain an access token.
|
Authenticate with Microsoft Graph API and obtain an access token.
|
||||||
|
|||||||
Reference in New Issue
Block a user