Files
ALwrity/backend/services/user_website_service.py
ajaysi b3cc83ed6e fix: resolve onboarding session not found warnings and frontend build OOM
- Use canonical Clerk user id (clerk_user_id) across all onboarding entrypoints to ensure consistent OnboardingSession.user_id lookup
- Fix API key persistence in api_key_manager.py to use correct APIKey model columns (session_id, provider, key)
- Increase Node heap for frontend build to 8GB and add build:nomap script to disable sourcemaps and reduce memory usage
- Update onboarding endpoints (endpoints_core.py, onboarding_control_service.py, step_management_service.py) to prefer clerk_user_id over id
- Fix frontend workflowStore.ts TypeScript error by returning WorkflowError instance
- Add website_automation_service.py for onboarding automation
2026-03-09 13:36:34 +05:30

296 lines
11 KiB
Python

"""User Website Service for ALwrity website maker functionality."""
from typing import Optional, Dict, Any, List
from sqlalchemy.orm import Session
from sqlalchemy import desc
from loguru import logger
from datetime import datetime
from models.onboarding import UserWebsite
from models.user_website_request import (
UserWebsiteRequest,
UserWebsiteResponse,
WebsiteStatus,
TemplateType,
WebsiteStatusUpdate
)
from services.database import get_db
class UserWebsiteService:
"""Service for managing user website creation and deployment."""
def __init__(self):
logger.info("🔄 Initializing UserWebsiteService...")
def create_user_website(self, request: UserWebsiteRequest) -> UserWebsiteResponse:
"""Create a new user website record."""
try:
logger.info(f"Creating website record for user {request.user_id}")
# For testing, create a session directly
from services.database import get_session_for_user
db = get_session_for_user(str(request.user_id))
if not db:
logger.error(f"Could not create database session for user {request.user_id}")
raise Exception("Database session creation failed")
try:
# Check if user already has a website
existing_website = db.query(UserWebsite).filter(
UserWebsite.user_id == request.user_id
).first()
if existing_website:
logger.info(f"User {request.user_id} already has website ID {existing_website.id}, updating it")
# Update existing record
existing_website.template_type = request.template_type.value
existing_website.business_name = request.business_name
existing_website.business_description = request.business_description
existing_website.status = request.status.value
existing_website.site_brief = request.site_brief
existing_website.theme_tokens = request.theme_tokens
existing_website.custom_css = request.custom_css
existing_website.deployment_config = request.deployment_config
existing_website.updated_at = datetime.utcnow()
db.commit()
db.refresh(existing_website)
logger.success(f"Updated website record for user {request.user_id}")
return UserWebsiteResponse(**existing_website.to_dict())
# Create new website record
db_website = UserWebsite(
user_id=request.user_id,
template_type=request.template_type.value,
business_name=request.business_name,
business_description=request.business_description,
status=request.status.value,
site_brief=request.site_brief,
theme_tokens=request.theme_tokens,
custom_css=request.custom_css,
deployment_config=request.deployment_config
)
db.add(db_website)
db.commit()
db.refresh(db_website)
logger.success(f"Created website record {db_website.id} for user {request.user_id}")
return UserWebsiteResponse(**db_website.to_dict())
finally:
db.close()
except Exception as e:
logger.error(f"Failed to create website record for user {request.user_id}: {str(e)}")
raise
def get_user_website_by_user(self, user_id: int) -> Optional[UserWebsiteResponse]:
"""Get website record by user ID."""
try:
logger.debug(f"Retrieving website for user {user_id}")
# For testing, create a session directly
from services.database import get_session_for_user
db = get_session_for_user(str(user_id))
if not db:
logger.warning(f"Could not create database session for user {user_id}")
return None
try:
website = db.query(UserWebsite).filter(
UserWebsite.user_id == user_id
).first()
if website:
logger.debug(f"Found website {website.id} for user {user_id}")
return UserWebsiteResponse(**website.to_dict())
logger.debug(f"No website found for user {user_id}")
return None
finally:
db.close()
except Exception as e:
logger.error(f"Failed to get website for user {user_id}: {str(e)}")
return None
def get_user_website_by_id(self, website_id: int) -> Optional[UserWebsiteResponse]:
"""Get website record by website ID."""
db: Session = next(get_db())
try:
logger.debug(f"Retrieving website {website_id}")
website = db.query(UserWebsite).filter(
UserWebsite.id == website_id
).first()
if website:
logger.debug(f"Found website {website_id}")
return UserWebsiteResponse(**website.to_dict())
logger.debug(f"Website {website_id} not found")
return None
except Exception as e:
logger.error(f"Failed to get website {website_id}: {str(e)}")
return None
finally:
db.close()
def update_user_website_status(
self,
user_id: int,
status_update: WebsiteStatusUpdate
) -> Optional[UserWebsiteResponse]:
"""Update website status and related fields."""
db: Session = next(get_db())
try:
logger.info(f"Updating website status for user {user_id} to {status_update.status}")
website = db.query(UserWebsite).filter(
UserWebsite.user_id == user_id
).first()
if not website:
logger.warning(f"No website found for user {user_id}")
return None
# Update fields
website.status = status_update.status.value
website.updated_at = datetime.utcnow()
if status_update.github_repo_url is not None:
website.github_repo_url = status_update.github_repo_url
if status_update.netlify_site_url is not None:
website.netlify_site_url = status_update.netlify_site_url
if status_update.netlify_admin_url is not None:
website.netlify_admin_url = status_update.netlify_admin_url
if status_update.preview_url is not None:
website.preview_url = status_update.preview_url
if status_update.error_message is not None:
website.error_message = status_update.error_message
db.commit()
db.refresh(website)
logger.success(f"Updated website {website.id} status to {status_update.status}")
return UserWebsiteResponse(**website.to_dict())
except Exception as e:
db.rollback()
logger.error(f"Failed to update website status for user {user_id}: {str(e)}")
raise
finally:
db.close()
def update_user_website_content(
self,
user_id: int,
site_brief: Optional[Dict[str, Any]] = None,
theme_tokens: Optional[Dict[str, Any]] = None,
custom_css: Optional[str] = None
) -> Optional[UserWebsiteResponse]:
"""Update website content (site brief, theme, CSS)."""
db: Session = next(get_db())
try:
logger.info(f"Updating website content for user {user_id}")
website = db.query(UserWebsite).filter(
UserWebsite.user_id == user_id
).first()
if not website:
logger.warning(f"No website found for user {user_id}")
return None
if site_brief is not None:
website.site_brief = site_brief
if theme_tokens is not None:
website.theme_tokens = theme_tokens
if custom_css is not None:
website.custom_css = custom_css
website.updated_at = datetime.utcnow()
db.commit()
db.refresh(website)
logger.success(f"Updated website {website.id} content")
return UserWebsiteResponse(**website.to_dict())
except Exception as e:
db.rollback()
logger.error(f"Failed to update website content for user {user_id}: {str(e)}")
raise
finally:
db.close()
def delete_user_website(self, user_id: int) -> bool:
"""Delete user website record."""
db: Session = next(get_db())
try:
logger.info(f"Deleting website for user {user_id}")
website = db.query(UserWebsite).filter(
UserWebsite.user_id == user_id
).first()
if not website:
logger.warning(f"No website found for user {user_id}")
return False
db.delete(website)
db.commit()
logger.success(f"Deleted website {website.id} for user {user_id}")
return True
except Exception as e:
db.rollback()
logger.error(f"Failed to delete website for user {user_id}: {str(e)}")
raise
finally:
db.close()
def get_all_user_websites(self, user_id: int) -> List[UserWebsiteResponse]:
"""Get all websites for a user (for history/audit)."""
db: Session = next(get_db())
try:
logger.debug(f"Retrieving all websites for user {user_id}")
websites = db.query(UserWebsite).filter(
UserWebsite.user_id == user_id
).order_by(desc(UserWebsite.created_at)).all()
return [UserWebsiteResponse(**website.to_dict()) for website in websites]
except Exception as e:
logger.error(f"Failed to get websites for user {user_id}: {str(e)}")
return []
finally:
db.close()
def get_websites_by_status(self, status: WebsiteStatus) -> List[UserWebsiteResponse]:
"""Get all websites with a specific status (for admin/monitoring)."""
db: Session = next(get_db())
try:
logger.debug(f"Retrieving websites with status {status}")
websites = db.query(UserWebsite).filter(
UserWebsite.status == status.value
).order_by(desc(UserWebsite.created_at)).all()
return [UserWebsiteResponse(**website.to_dict()) for website in websites]
except Exception as e:
logger.error(f"Failed to get websites with status {status}: {str(e)}")
return []
finally:
db.close()
# Singleton instance
user_website_service = UserWebsiteService()