fix: store login crash and dashboard misrouted as storefront
Some checks failed
Some checks failed
- Seed default RBAC roles per store and assign role_id to StoreUser records (was never implemented after RBAC Phase 1 cleanup) - Handle nullable role in auth_service find_user_store and get_user_store_role to prevent NoneType crash on login - Use platform_clean_path instead of clean_path in FrontendTypeMiddleware so /store/X/dashboard is detected as STORE, not STOREFRONT Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -221,6 +221,7 @@ DEMO_SUBSCRIPTIONS = [
|
||||
]
|
||||
|
||||
# Demo team members (linked to merchants by index, assigned to stores by store_code)
|
||||
# Role must be one of: manager, staff, support, viewer, marketing (see ROLE_PRESETS)
|
||||
DEMO_TEAM_MEMBERS = [
|
||||
# WizaCorp team
|
||||
{
|
||||
@@ -229,6 +230,7 @@ DEMO_TEAM_MEMBERS = [
|
||||
"password": "password123", # noqa: SEC001
|
||||
"first_name": "Alice",
|
||||
"last_name": "Manager",
|
||||
"role": "manager",
|
||||
"store_codes": ["WIZATECH", "WIZAGADGETS"], # manages two stores
|
||||
},
|
||||
{
|
||||
@@ -237,6 +239,7 @@ DEMO_TEAM_MEMBERS = [
|
||||
"password": "password123", # noqa: SEC001
|
||||
"first_name": "Charlie",
|
||||
"last_name": "Staff",
|
||||
"role": "staff",
|
||||
"store_codes": ["WIZAHOME"],
|
||||
},
|
||||
# Fashion Group team
|
||||
@@ -246,6 +249,7 @@ DEMO_TEAM_MEMBERS = [
|
||||
"password": "password123", # noqa: SEC001
|
||||
"first_name": "Diana",
|
||||
"last_name": "Stylist",
|
||||
"role": "manager",
|
||||
"store_codes": ["FASHIONHUB", "FASHIONOUTLET"],
|
||||
},
|
||||
{
|
||||
@@ -254,6 +258,7 @@ DEMO_TEAM_MEMBERS = [
|
||||
"password": "password123", # noqa: SEC001
|
||||
"first_name": "Eric",
|
||||
"last_name": "Sales",
|
||||
"role": "staff",
|
||||
"store_codes": ["FASHIONOUTLET"],
|
||||
},
|
||||
# BookWorld team
|
||||
@@ -263,6 +268,7 @@ DEMO_TEAM_MEMBERS = [
|
||||
"password": "password123", # noqa: SEC001
|
||||
"first_name": "Fiona",
|
||||
"last_name": "Editor",
|
||||
"role": "manager",
|
||||
"store_codes": ["BOOKSTORE", "BOOKDIGITAL"],
|
||||
},
|
||||
]
|
||||
@@ -853,10 +859,37 @@ def create_demo_stores(
|
||||
return stores
|
||||
|
||||
|
||||
def _ensure_store_roles(db: Session, store: Store) -> dict[str, Role]:
|
||||
"""Ensure default roles exist for a store, return name→Role lookup."""
|
||||
from app.modules.tenancy.services.permission_discovery_service import (
|
||||
permission_discovery_service,
|
||||
)
|
||||
|
||||
existing = db.query(Role).filter(Role.store_id == store.id).all()
|
||||
if existing:
|
||||
return {r.name: r for r in existing}
|
||||
|
||||
role_names = ["manager", "staff", "support", "viewer", "marketing"]
|
||||
roles = {}
|
||||
for name in role_names:
|
||||
permissions = list(permission_discovery_service.get_preset_permissions(name))
|
||||
role = Role(
|
||||
store_id=store.id,
|
||||
name=name,
|
||||
permissions=permissions,
|
||||
)
|
||||
db.add(role) # noqa: PERF006
|
||||
roles[name] = role
|
||||
|
||||
db.flush()
|
||||
print_success(f" Created default roles for {store.name}: {', '.join(role_names)}")
|
||||
return roles
|
||||
|
||||
|
||||
def create_demo_team_members(
|
||||
db: Session, stores: list[Store], auth_manager: AuthManager
|
||||
) -> list[User]:
|
||||
"""Create demo team member users and assign them to stores."""
|
||||
"""Create demo team member users and assign them to stores with roles."""
|
||||
|
||||
if SEED_MODE == "minimal":
|
||||
return []
|
||||
@@ -865,6 +898,15 @@ def create_demo_team_members(
|
||||
# Build a store_code → Store lookup from the created stores
|
||||
store_lookup = {s.store_code: s for s in stores}
|
||||
|
||||
# Pre-create default roles for all stores that team members will be assigned to
|
||||
store_roles: dict[str, dict[str, Role]] = {}
|
||||
for member_data in DEMO_TEAM_MEMBERS:
|
||||
for store_code in member_data["store_codes"]:
|
||||
if store_code not in store_roles:
|
||||
store = store_lookup.get(store_code)
|
||||
if store:
|
||||
store_roles[store_code] = _ensure_store_roles(db, store)
|
||||
|
||||
for member_data in DEMO_TEAM_MEMBERS:
|
||||
# Check if user already exists
|
||||
user = db.execute(
|
||||
@@ -894,7 +936,8 @@ def create_demo_team_members(
|
||||
|
||||
team_users.append(user)
|
||||
|
||||
# Assign user to stores
|
||||
# Assign user to stores with role
|
||||
role_name = member_data["role"]
|
||||
for store_code in member_data["store_codes"]:
|
||||
store = store_lookup.get(store_code)
|
||||
if not store:
|
||||
@@ -912,14 +955,20 @@ def create_demo_team_members(
|
||||
if existing_link:
|
||||
continue
|
||||
|
||||
# Look up role for this store
|
||||
role = store_roles.get(store_code, {}).get(role_name)
|
||||
|
||||
store_user = StoreUser(
|
||||
store_id=store.id,
|
||||
user_id=user.id,
|
||||
role_id=role.id if role else None,
|
||||
is_active=True,
|
||||
created_at=datetime.now(UTC),
|
||||
)
|
||||
db.add(store_user) # noqa: PERF006
|
||||
print_success(f" Assigned {user.first_name} to {store.name} as team member")
|
||||
print_success(
|
||||
f" Assigned {user.first_name} to {store.name} as {role_name}"
|
||||
)
|
||||
|
||||
db.flush()
|
||||
return team_users
|
||||
|
||||
Reference in New Issue
Block a user