# app/modules/tenancy/routes/pages/store.py """ Tenancy Store Page Routes (HTML rendering). Store pages for authentication and account management: - Root redirect - Login - Team management - Profile - Settings """ from fastapi import APIRouter, Depends, Query, Request from fastapi.responses import HTMLResponse, RedirectResponse from sqlalchemy.orm import Session from app.api.deps import ( get_current_store_from_cookie_or_header, get_current_store_optional, get_db, get_resolved_store_code, require_store_page_permission, ) from app.modules.core.utils.page_context import get_store_context from app.modules.tenancy.models import User from app.templates_config import templates from app.utils.i18n import get_jinja2_globals router = APIRouter() # ============================================================================ # PUBLIC ROUTES (No Authentication Required) # ============================================================================ @router.get("/", response_class=RedirectResponse, include_in_schema=False) async def store_root( store_code: str = Depends(get_resolved_store_code), current_user: User | None = Depends(get_current_store_optional), ): """ Redirect /store/ or /store/{code}/ based on authentication status. - Authenticated store users -> /store/{code}/dashboard - Unauthenticated users -> /store/{code}/login """ if current_user: return RedirectResponse( url=f"/store/{store_code}/dashboard", status_code=302 ) return RedirectResponse(url=f"/store/{store_code}/login", status_code=302) @router.get( "/login", response_class=HTMLResponse, include_in_schema=False ) async def store_login_page( request: Request, store_code: str = Depends(get_resolved_store_code), current_user: User | None = Depends(get_current_store_optional), ): """ Render store login page. If user is already authenticated on the SAME platform, redirect to dashboard. If authenticated on a DIFFERENT platform, show login form so the user can re-login with the correct platform context. """ language = getattr(request.state, "language", "fr") platform = getattr(request.state, "platform", None) platform_code = platform.code if platform else None if current_user: # If the URL's platform matches the JWT's platform (or no platform in URL), # redirect to dashboard. Otherwise, show login form for platform switch. jwt_platform = current_user.token_platform_code same_platform = ( platform_code is None or jwt_platform is None or platform_code == jwt_platform ) if same_platform: if platform_code: redirect_url = f"/platforms/{platform_code}/store/{store_code}/dashboard" else: redirect_url = f"/store/{store_code}/dashboard" return RedirectResponse(url=redirect_url, status_code=302) return templates.TemplateResponse( "tenancy/store/login.html", { "request": request, "store_code": store_code, "platform_code": platform_code, "frontend_type": "store", **get_jinja2_globals(language), }, ) @router.get( "/invitation/accept", response_class=HTMLResponse, include_in_schema=False ) async def store_invitation_accept_page( request: Request, token: str = Query(..., description="Invitation token from email"), store_code: str = Depends(get_resolved_store_code), db: Session = Depends(get_db), ): """ Render invitation acceptance page. Public route — no auth required. Validates the token and shows a form to review name and set password. """ from app.modules.tenancy.services.store_team_service import store_team_service language = getattr(request.state, "language", "en") platform_code = getattr(request.state, "platform_code", None) # Get invitation info (without accepting it) info = store_team_service.get_invitation_info(db, token) return templates.TemplateResponse( "tenancy/store/invitation-accept.html", { "request": request, "store_code": store_code, "platform_code": platform_code, "frontend_type": "store", "token": token, "invitation": info, **get_jinja2_globals(language), }, ) # ============================================================================ # AUTHENTICATED ROUTES (Store Users Only) # ============================================================================ @router.get( "/team", response_class=HTMLResponse, include_in_schema=False ) async def store_team_page( request: Request, store_code: str = Depends(get_resolved_store_code), current_user: User = Depends(require_store_page_permission("team.view")), db: Session = Depends(get_db), ): """ Render team management page. JavaScript loads team members via API. """ return templates.TemplateResponse( "tenancy/store/team.html", get_store_context(request, db, current_user, store_code), ) @router.get( "/team/roles", response_class=HTMLResponse, include_in_schema=False ) async def store_roles_page( request: Request, store_code: str = Depends(get_resolved_store_code), current_user: User = Depends(require_store_page_permission("team.view")), db: Session = Depends(get_db), ): """ Render role editor page. Store owners can create, edit, and delete custom roles with a permission matrix UI. """ return templates.TemplateResponse( "tenancy/store/roles.html", get_store_context(request, db, current_user, store_code), ) @router.get( "/my-account", response_class=HTMLResponse, include_in_schema=False ) async def store_my_account_page( request: Request, store_code: str = Depends(get_resolved_store_code), current_user: User = Depends(get_current_store_from_cookie_or_header), db: Session = Depends(get_db), ): """Render the store user's personal account page.""" return templates.TemplateResponse( "tenancy/store/my-account.html", get_store_context(request, db, current_user, store_code), ) @router.get( "/profile", response_class=HTMLResponse, include_in_schema=False ) async def store_profile_page( request: Request, store_code: str = Depends(get_resolved_store_code), current_user: User = Depends(get_current_store_from_cookie_or_header), db: Session = Depends(get_db), ): """ Render store profile page. User can manage their personal profile information. """ return templates.TemplateResponse( "tenancy/store/profile.html", get_store_context(request, db, current_user, store_code), ) @router.get( "/settings", response_class=HTMLResponse, include_in_schema=False ) async def store_settings_page( request: Request, store_code: str = Depends(get_resolved_store_code), current_user: User = Depends(get_current_store_from_cookie_or_header), db: Session = Depends(get_db), ): """ Render store settings page. JavaScript loads settings via API. """ return templates.TemplateResponse( "tenancy/store/settings.html", get_store_context(request, db, current_user, store_code), )