chore: fix email retrieval for oauth users

This commit is contained in:
Saumya 2025-09-10 16:24:40 +05:30
parent db6953b4dc
commit 6dd69c00c2
6 changed files with 253 additions and 6 deletions

View File

@ -74,6 +74,7 @@ async def advanced_user_search(
'''
id,
created_at,
primary_owner_user_id,
billing_customers(email),
billing_subscriptions(status)
'''
@ -168,10 +169,21 @@ async def advanced_user_search(
subscription_status = item['billing_subscriptions'][0].get('status')
credit_account = credit_accounts.get(item['id'], {})
email = 'N/A'
if item.get('billing_customers') and item['billing_customers'][0].get('email'):
email = item['billing_customers'][0]['email']
elif item.get('primary_owner_user_id'):
try:
user_email_result = await client.rpc('get_user_email', {'user_id': item['primary_owner_user_id']}).execute()
if user_email_result.data:
email = user_email_result.data
except Exception as e:
logger.warning(f"Failed to get email for account {item['id']}: {e}")
users.append(UserSummary(
id=item['id'],
email=item['billing_customers'][0]['email'] if item.get('billing_customers') else 'N/A',
email=email,
created_at=datetime.fromisoformat(item['created_at'].replace('Z', '+00:00')),
tier=credit_account.get('tier', 'free'),
credit_balance=float(credit_account.get('balance', 0)),
@ -227,6 +239,7 @@ async def list_users(
'''
id,
created_at,
primary_owner_user_id,
billing_customers(email),
billing_subscriptions(status)
'''
@ -238,6 +251,7 @@ async def list_users(
'''
id,
created_at,
primary_owner_user_id,
billing_customers(email),
billing_subscriptions(status)
'''
@ -305,9 +319,22 @@ async def list_users(
credit_account = credit_accounts.get(item['id'], {})
# Get email from billing_customers or fetch from auth.users for OAuth users
email = 'N/A'
if item.get('billing_customers') and item['billing_customers'][0].get('email'):
email = item['billing_customers'][0]['email']
elif item.get('primary_owner_user_id'):
# Try to get email for OAuth users
try:
user_email_result = await client.rpc('get_user_email', {'user_id': item['primary_owner_user_id']}).execute()
if user_email_result.data:
email = user_email_result.data
except Exception as e:
logger.warning(f"Failed to get email for account {item['id']}: {e}")
users.append(UserSummary(
id=item['id'],
email=item['billing_customers'][0]['email'] if item.get('billing_customers') else 'N/A',
email=email,
created_at=datetime.fromisoformat(item['created_at'].replace('Z', '+00:00')),
tier=credit_account.get('tier', 'free'),
credit_balance=float(credit_account.get('balance', 0)),
@ -340,6 +367,7 @@ async def get_user_details(
'''
id,
created_at,
primary_owner_user_id,
billing_customers(email),
billing_subscriptions(status, created, current_period_end)
'''
@ -350,6 +378,18 @@ async def get_user_details(
account = account_result.data[0]
# Get email if not present (OAuth users)
if not account.get('billing_customers') or not account['billing_customers'][0].get('email'):
if account.get('primary_owner_user_id'):
try:
user_email_result = await client.rpc('get_user_email', {'user_id': account['primary_owner_user_id']}).execute()
if user_email_result.data:
if not account.get('billing_customers'):
account['billing_customers'] = [{}]
account['billing_customers'][0]['email'] = user_email_result.data
except Exception as e:
logger.warning(f"Failed to get email for account {user_id}: {e}")
credit_result = await client.from_('credit_accounts').select(
'balance, tier, lifetime_granted, lifetime_purchased, lifetime_used, last_grant_date'
).eq('account_id', user_id).execute()

View File

@ -42,9 +42,29 @@ class SubscriptionService:
account = account_result.data[0]
user_id = account['primary_owner_user_id']
email = None
user_result = await client.auth.admin.get_user_by_id(user_id)
email = user_result.user.email if user_result and user_result.user else None
try:
user_result = await client.auth.admin.get_user_by_id(user_id)
email = user_result.user.email if user_result and user_result.user else None
except Exception as e:
logger.warning(f"Failed to get user via auth.admin API for user {user_id}: {e}")
if not email:
try:
user_email_result = await client.rpc('get_user_email', {'user_id': user_id}).execute()
if user_email_result.data:
email = user_email_result.data
except Exception as e:
logger.warning(f"Failed to get email via RPC for user {user_id}: {e}")
if not email:
logger.error(f"Could not find email for user {user_id} / account {account_id}")
raise HTTPException(
status_code=400,
detail="Unable to retrieve user email. Please ensure your account has a valid email address."
)
customer = await stripe.Customer.create_async(
email=email,
@ -57,7 +77,7 @@ class SubscriptionService:
'email': email
}).execute()
logger.info(f"Created Stripe customer {customer.id} for account {account_id}")
logger.info(f"Created Stripe customer {customer.id} for account {account_id} with email {email}")
return customer.id
async def get_subscription(self, account_id: str) -> Dict:

View File

@ -0,0 +1,90 @@
-- NOTE: This migration has been rolled back by 20250910103000_rollback_oauth_email_fix.sql
BEGIN;
CREATE OR REPLACE FUNCTION public.get_user_email(user_id UUID)
RETURNS TEXT
LANGUAGE plpgsql
SECURITY DEFINER
SET search_path = public
AS $$
DECLARE
user_email TEXT;
BEGIN
SELECT email INTO user_email
FROM auth.users
WHERE id = user_id;
IF user_email IS NULL THEN
SELECT
COALESCE(
raw_user_meta_data->>'email',
raw_user_meta_data->>'user_email',
email
) INTO user_email
FROM auth.users
WHERE id = user_id;
END IF;
RETURN user_email;
END;
$$;
GRANT EXECUTE ON FUNCTION public.get_user_email(UUID) TO authenticated, service_role;
DO $$
DECLARE
rec RECORD;
user_email TEXT;
BEGIN
FOR rec IN
SELECT bc.account_id, a.primary_owner_user_id
FROM basejump.billing_customers bc
JOIN basejump.accounts a ON bc.account_id = a.id
WHERE bc.email IS NULL OR bc.email = ''
LOOP
user_email := public.get_user_email(rec.primary_owner_user_id);
IF user_email IS NOT NULL THEN
UPDATE basejump.billing_customers
SET email = user_email
WHERE account_id = rec.account_id;
RAISE NOTICE 'Updated email for account %: %', rec.account_id, user_email;
END IF;
END LOOP;
END;
$$;
CREATE INDEX IF NOT EXISTS idx_auth_users_email ON auth.users(email);
CREATE OR REPLACE FUNCTION basejump.ensure_billing_customer_email()
RETURNS TRIGGER
LANGUAGE plpgsql
AS $$
DECLARE
user_email TEXT;
owner_id UUID;
BEGIN
IF NEW.email IS NULL OR NEW.email = '' THEN
SELECT primary_owner_user_id INTO owner_id
FROM basejump.accounts
WHERE id = NEW.account_id;
user_email := public.get_user_email(owner_id);
IF user_email IS NOT NULL THEN
NEW.email := user_email;
END IF;
END IF;
RETURN NEW;
END;
$$;
DROP TRIGGER IF EXISTS ensure_billing_customer_email_trigger ON basejump.billing_customers;
CREATE TRIGGER ensure_billing_customer_email_trigger
BEFORE INSERT OR UPDATE ON basejump.billing_customers
FOR EACH ROW
EXECUTE FUNCTION basejump.ensure_billing_customer_email();
COMMIT;

View File

@ -0,0 +1,9 @@
BEGIN;
DROP TRIGGER IF EXISTS ensure_billing_customer_email_trigger ON basejump.billing_customers;
DROP FUNCTION IF EXISTS basejump.ensure_billing_customer_email();
DROP FUNCTION IF EXISTS public.get_user_email(UUID);
COMMIT;

View File

@ -0,0 +1,89 @@
BEGIN;
CREATE OR REPLACE FUNCTION public.get_user_email(user_id UUID)
RETURNS TEXT
LANGUAGE plpgsql
SECURITY DEFINER
SET search_path = public
AS $$
DECLARE
user_email TEXT;
BEGIN
SELECT email INTO user_email
FROM auth.users
WHERE id = user_id;
IF user_email IS NULL THEN
SELECT
COALESCE(
raw_user_meta_data->>'email',
raw_user_meta_data->>'user_email',
email
) INTO user_email
FROM auth.users
WHERE id = user_id;
END IF;
RETURN user_email;
END;
$$;
GRANT EXECUTE ON FUNCTION public.get_user_email(UUID) TO authenticated, service_role;
DO $$
DECLARE
rec RECORD;
user_email TEXT;
BEGIN
FOR rec IN
SELECT bc.account_id, a.primary_owner_user_id
FROM basejump.billing_customers bc
JOIN basejump.accounts a ON bc.account_id = a.id
WHERE bc.email IS NULL OR bc.email = ''
LOOP
user_email := public.get_user_email(rec.primary_owner_user_id);
IF user_email IS NOT NULL THEN
UPDATE basejump.billing_customers
SET email = user_email
WHERE account_id = rec.account_id;
RAISE NOTICE 'Updated email for account %: %', rec.account_id, user_email;
END IF;
END LOOP;
END;
$$;
CREATE INDEX IF NOT EXISTS idx_auth_users_email ON auth.users(email);
CREATE OR REPLACE FUNCTION basejump.ensure_billing_customer_email()
RETURNS TRIGGER
LANGUAGE plpgsql
AS $$
DECLARE
user_email TEXT;
owner_id UUID;
BEGIN
IF NEW.email IS NULL OR NEW.email = '' THEN
SELECT primary_owner_user_id INTO owner_id
FROM basejump.accounts
WHERE id = NEW.account_id;
user_email := public.get_user_email(owner_id);
IF user_email IS NOT NULL THEN
NEW.email := user_email;
END IF;
END IF;
RETURN NEW;
END;
$$;
DROP TRIGGER IF EXISTS ensure_billing_customer_email_trigger ON basejump.billing_customers;
CREATE TRIGGER ensure_billing_customer_email_trigger
BEFORE INSERT OR UPDATE ON basejump.billing_customers
FOR EACH ROW
EXECUTE FUNCTION basejump.ensure_billing_customer_email();
COMMIT;

View File

@ -359,7 +359,6 @@ export function AdminUserDetailsDialog({
</CardContent>
</Card>
</TabsContent>
<TabsContent value="actions" className="space-y-4">
<div className="grid grid-cols-1 gap-4">
<Card>