aivideodubbingapi-r08gi1/alembic/versions/004_add_google_oauth_fields.py
Automated Action 99937b3fd7 Add comprehensive Google OAuth integration for easy login/signup
Features:
- Complete Google OAuth 2.0 integration with ID token and authorization code flows
- Enhanced User model with Google OAuth fields (google_id, is_google_user, email_verified, profile_picture)
- Google OAuth service for token verification and user info extraction
- Multiple authentication endpoints:
  - GET /auth/google/oauth-url (get OAuth URL for frontend)
  - POST /auth/google/login-with-token (direct ID token login)
  - POST /auth/google/login-with-code (authorization code exchange)
- Smart user handling: creates new users or links existing accounts
- Issues own JWT tokens after Google authentication
- Database migration 004 for Google OAuth fields
- Enhanced login logic to handle Google vs password users
- Comprehensive README with Google OAuth setup instructions
- Frontend integration examples for both OAuth flows

Google OAuth automatically:
- Creates user accounts on first login
- Links existing email accounts to Google
- Extracts profile information (name, picture, locale)
- Verifies email addresses
- Issues secure JWT tokens for API access
2025-06-25 05:49:54 +00:00

81 lines
2.7 KiB
Python

"""Add Google OAuth fields to users table
Revision ID: 004
Revises: 003
Create Date: 2024-01-01 00:00:03.000000
"""
from typing import Sequence, Union
from alembic import op
import sqlalchemy as sa
from sqlalchemy.engine.reflection import Inspector
# revision identifiers, used by Alembic.
revision: str = '004'
down_revision: Union[str, None] = '003'
branch_labels: Union[str, Sequence[str], None] = None
depends_on: Union[str, Sequence[str], None] = None
def column_exists(table_name, column_name):
"""Check if a column exists in a table"""
bind = op.get_bind()
inspector = Inspector.from_engine(bind)
columns = [c['name'] for c in inspector.get_columns(table_name)]
return column_name in columns
def upgrade() -> None:
# List of Google OAuth columns to add
google_oauth_columns = [
('google_id', sa.Column('google_id', sa.String(), nullable=True)),
('is_google_user', sa.Column('is_google_user', sa.Boolean(), nullable=True)),
('email_verified', sa.Column('email_verified', sa.Boolean(), nullable=True)),
('profile_picture', sa.Column('profile_picture', sa.String(), nullable=True))
]
# Add Google OAuth columns only if they don't exist
for column_name, column_def in google_oauth_columns:
if not column_exists('users', column_name):
op.add_column('users', column_def)
# Create index for google_id if column exists
if column_exists('users', 'google_id'):
try:
op.create_index(op.f('ix_users_google_id'), 'users', ['google_id'], unique=True)
except Exception:
# Index might already exist, ignore
pass
# Set default values for existing users
if column_exists('users', 'is_google_user'):
op.execute("UPDATE users SET is_google_user = 0 WHERE is_google_user IS NULL")
if column_exists('users', 'email_verified'):
op.execute("UPDATE users SET email_verified = 0 WHERE email_verified IS NULL")
# Make password_hash nullable for Google OAuth users
# Note: SQLite doesn't support modifying column constraints directly
# So we'll handle this in the application logic
def downgrade() -> None:
# List of columns to remove (in reverse order)
google_oauth_columns = [
'profile_picture',
'email_verified',
'is_google_user',
'google_id'
]
# Drop index first if it exists
try:
op.drop_index(op.f('ix_users_google_id'), table_name='users')
except Exception:
# Index might not exist, ignore
pass
# Remove columns only if they exist
for column_name in google_oauth_columns:
if column_exists('users', column_name):
op.drop_column('users', column_name)