176 lines
5.9 KiB
Python
176 lines
5.9 KiB
Python
import httpx
|
|
from sqlalchemy.orm import Session
|
|
from uuid import UUID
|
|
import models
|
|
import re
|
|
|
|
|
|
def normalize_phone_number(phone: str) -> str:
|
|
"""
|
|
Convert phone numbers from +972 format to Israeli 0 format
|
|
Examples:
|
|
+972501234567 -> 0501234567
|
|
+972-50-123-4567 -> 0501234567
|
|
972501234567 -> 0501234567
|
|
"""
|
|
if not phone:
|
|
return phone
|
|
|
|
# Remove all non-digit characters except +
|
|
cleaned = re.sub(r'[^\d+]', '', phone)
|
|
|
|
# Handle +972 format
|
|
if cleaned.startswith('+972'):
|
|
# Remove +972 and add 0 prefix
|
|
return '0' + cleaned[4:]
|
|
elif cleaned.startswith('972'):
|
|
# Remove 972 and add 0 prefix
|
|
return '0' + cleaned[3:]
|
|
|
|
# If already starts with 0, return as is
|
|
if cleaned.startswith('0'):
|
|
return cleaned
|
|
|
|
# If it's a 9-digit number (Israeli mobile without prefix), add 0
|
|
if len(cleaned) == 9 and cleaned[0] in '5789':
|
|
return '0' + cleaned
|
|
|
|
return cleaned
|
|
|
|
|
|
async def import_contacts_from_google(
|
|
access_token: str,
|
|
db: Session,
|
|
owner_email: str = None,
|
|
added_by_user_id: str = None,
|
|
event_id: str = None
|
|
) -> int:
|
|
"""
|
|
Import contacts from Google People API
|
|
|
|
Args:
|
|
access_token: OAuth 2.0 access token from Google
|
|
db: Database session
|
|
owner_email: Email of the account importing (stored as owner in DB)
|
|
added_by_user_id: UUID of the user adding these contacts (required for DB)
|
|
event_id: Event ID to scope import to (required)
|
|
|
|
Returns:
|
|
Number of contacts imported
|
|
"""
|
|
from uuid import UUID
|
|
|
|
# event_id and added_by_user_id are required
|
|
if not event_id:
|
|
raise ValueError("event_id is required for contact imports")
|
|
if not added_by_user_id:
|
|
raise ValueError("added_by_user_id is required for contact imports")
|
|
|
|
# Convert to UUID
|
|
event_uuid = UUID(event_id)
|
|
user_uuid = UUID(added_by_user_id)
|
|
headers = {
|
|
"Authorization": f"Bearer {access_token}"
|
|
}
|
|
|
|
# Google People API endpoint
|
|
url = "https://people.googleapis.com/v1/people/me/connections"
|
|
params = {
|
|
"personFields": "names,phoneNumbers,emailAddresses",
|
|
"pageSize": 1000
|
|
}
|
|
|
|
imported_count = 0
|
|
|
|
async with httpx.AsyncClient() as client:
|
|
response = await client.get(url, headers=headers, params=params)
|
|
|
|
if response.status_code != 200:
|
|
# Try to parse error details
|
|
try:
|
|
error_data = response.json()
|
|
if 'error' in error_data:
|
|
error_info = error_data['error']
|
|
error_code = error_info.get('code')
|
|
error_message = error_info.get('message')
|
|
error_status = error_info.get('status')
|
|
|
|
if error_code == 403 or error_status == 'PERMISSION_DENIED':
|
|
raise Exception(
|
|
f"Google People API is not enabled or you don't have permission. "
|
|
f"Enable the People API in Google Cloud Console."
|
|
)
|
|
else:
|
|
raise Exception(f"Google API Error: {error_status} - {error_message}")
|
|
except ValueError:
|
|
raise Exception(f"Failed to fetch contacts: {response.text}")
|
|
|
|
data = response.json()
|
|
connections = data.get("connections", [])
|
|
|
|
for connection in connections:
|
|
# Extract name
|
|
names = connection.get("names", [])
|
|
if not names:
|
|
continue
|
|
|
|
name = names[0]
|
|
first_name = name.get("givenName", "")
|
|
last_name = name.get("familyName", "")
|
|
|
|
if not first_name and not last_name:
|
|
continue
|
|
|
|
# Extract email
|
|
emails = connection.get("emailAddresses", [])
|
|
email = emails[0].get("value") if emails else None
|
|
|
|
# Extract phone number
|
|
phones = connection.get("phoneNumbers", [])
|
|
phone_number = phones[0].get("value") if phones else None
|
|
|
|
# Normalize phone number to Israeli format (0...)
|
|
if phone_number:
|
|
phone_number = normalize_phone_number(phone_number)
|
|
|
|
# Check if contact already exists by email OR phone number
|
|
existing = None
|
|
if email:
|
|
existing = db.query(models.Guest).filter(
|
|
models.Guest.event_id == event_uuid,
|
|
models.Guest.email == email
|
|
).first()
|
|
if not existing and phone_number:
|
|
existing = db.query(models.Guest).filter(
|
|
models.Guest.event_id == event_uuid,
|
|
models.Guest.phone_number == phone_number
|
|
).first()
|
|
|
|
if existing:
|
|
# Contact exists - update owner if needed
|
|
if existing.owner_email != owner_email:
|
|
existing.owner_email = owner_email
|
|
db.add(existing)
|
|
else:
|
|
# Create new guest
|
|
guest_data = {
|
|
"first_name": first_name or "Unknown",
|
|
"last_name": last_name or "",
|
|
"email": email,
|
|
"phone_number": phone_number,
|
|
"phone": phone_number, # Also set old phone column for backward compat
|
|
"rsvp_status": "invited",
|
|
"owner_email": owner_email,
|
|
"source": "google",
|
|
"event_id": event_uuid,
|
|
"added_by_user_id": user_uuid
|
|
}
|
|
|
|
guest = models.Guest(**guest_data)
|
|
db.add(guest)
|
|
imported_count += 1
|
|
|
|
db.commit()
|
|
|
|
return imported_count
|