Add Google Contacts integration and fix critical Windows issues

- Add People API integration with contact management tools (create, list, get)
- Fix OAuth flow: replace deprecated OOB with localhost callback
- Fix Ctrl+C handling with proper signal handlers for graceful shutdown
- Fix UTF-8 encoding in scheduled_tasks.py for Windows compatibility
- Add users/ directory to gitignore to protect personal data

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
2026-02-14 15:12:01 -07:00
parent 19af20e700
commit 0eb5d2cab4
7 changed files with 557 additions and 52 deletions

View File

@@ -1,4 +1,4 @@
"""OAuth2 Manager for Google APIs (Gmail, Calendar)."""
"""OAuth2 Manager for Google APIs (Gmail, Calendar, Contacts)."""
import json
import os
@@ -18,6 +18,7 @@ from google_auth_oauthlib.flow import InstalledAppFlow
SCOPES = [
"https://www.googleapis.com/auth/gmail.modify",
"https://www.googleapis.com/auth/calendar",
"https://www.googleapis.com/auth/contacts",
]
# Token file location
@@ -155,47 +156,43 @@ class GoogleOAuthManager:
"client_secret": creds_config["client_secret"],
"auth_uri": "https://accounts.google.com/o/oauth2/auth",
"token_uri": "https://oauth2.googleapis.com/token",
"redirect_uris": ["http://localhost:8080"],
"redirect_uris": ["http://localhost:8081"],
}
}
if manual:
# Manual flow - user pastes code
flow = InstalledAppFlow.from_client_config(
client_config, SCOPES
)
self.credentials = flow.run_console()
else:
# Automated flow with local server
flow = InstalledAppFlow.from_client_config(
client_config, SCOPES
)
flow.redirect_uri = "http://localhost:8080"
# Both manual and automatic modes use local server
# (Google deprecated OOB flow in 2022)
flow = InstalledAppFlow.from_client_config(client_config, SCOPES)
flow.redirect_uri = "http://localhost:8081"
auth_url, _ = flow.authorization_url(prompt="consent")
auth_url, _ = flow.authorization_url(prompt="consent")
print("\nPlease visit this URL to authorize:")
print(f"\n{auth_url}\n")
print("\nPlease visit this URL to authorize:")
print(f"\n{auth_url}\n")
# Try to open browser automatically
# Auto-open browser unless manual mode
if not manual:
try:
webbrowser.open(auth_url)
print("Opening browser automatically...\n")
except Exception:
pass
print("Could not open browser automatically. Please visit the URL above.\n")
else:
print("Please open the URL above in your browser manually.\n")
# Start local server to receive callback
server = HTTPServer(("localhost", 8080), OAuthCallbackHandler)
print("Waiting for authorization... (press Ctrl+C to cancel)\n")
# Start local server to receive callback
server = HTTPServer(("localhost", 8081), OAuthCallbackHandler)
print("Waiting for authorization... (press Ctrl+C to cancel)\n")
# Wait for callback
server.handle_request()
# Wait for callback
server.handle_request()
if OAuthCallbackHandler.authorization_code:
flow.fetch_token(code=OAuthCallbackHandler.authorization_code)
self.credentials = flow.credentials
else:
print("[OAuth] Authorization failed - no code received")
return False
if OAuthCallbackHandler.authorization_code:
flow.fetch_token(code=OAuthCallbackHandler.authorization_code)
self.credentials = flow.credentials
else:
print("[OAuth] Authorization failed - no code received")
return False
# Save tokens
self._save_credentials()