feat: RBAC Phase 1 — consolidate user roles into 4-value enum
Some checks failed
Some checks failed
Consolidate User.role (2-value: admin/store) + User.is_super_admin (boolean) into a single 4-value UserRole enum: super_admin, platform_admin, merchant_owner, store_member. Drop stale StoreUser.user_type column. Fix role="user" bug in merchant creation. Key changes: - Expand UserRole enum from 2 to 4 values with computed properties (is_admin, is_super_admin, is_platform_admin, is_merchant_owner, is_store_user) - Add Alembic migration (tenancy_003) for data migration + column drops - Remove is_super_admin from JWT token payload - Update all auth dependencies, services, routes, templates, JS, and tests - Update all RBAC documentation 66 files changed, 1219 unit tests passing. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -25,7 +25,6 @@ class UserResponse(BaseModel):
|
||||
username: str
|
||||
role: str
|
||||
is_active: bool
|
||||
is_super_admin: bool = False
|
||||
preferred_language: str | None = None
|
||||
last_login: datetime | None = None
|
||||
created_at: datetime
|
||||
@@ -64,7 +63,7 @@ class StoreMembershipSummary(BaseModel):
|
||||
store_id: int
|
||||
store_code: str
|
||||
store_name: str
|
||||
user_type: str
|
||||
role: str
|
||||
is_active: bool
|
||||
|
||||
|
||||
@@ -88,7 +87,7 @@ class UserUpdate(BaseModel):
|
||||
email: EmailStr | None = None
|
||||
first_name: str | None = Field(None, max_length=100)
|
||||
last_name: str | None = Field(None, max_length=100)
|
||||
role: str | None = Field(None, pattern="^(admin|store)$")
|
||||
role: str | None = Field(None, pattern="^(super_admin|platform_admin|merchant_owner|store_member)$")
|
||||
is_active: bool | None = None
|
||||
is_email_verified: bool | None = None
|
||||
preferred_language: str | None = Field(
|
||||
@@ -113,7 +112,7 @@ class UserCreate(BaseModel):
|
||||
password: str = Field(..., min_length=6, description="Password")
|
||||
first_name: str | None = Field(None, max_length=100)
|
||||
last_name: str | None = Field(None, max_length=100)
|
||||
role: str = Field(default="store", pattern="^(admin|store)$")
|
||||
role: str = Field(default="store_member", pattern="^(super_admin|platform_admin|merchant_owner|store_member)$")
|
||||
preferred_language: str | None = Field(
|
||||
None, description="Preferred language (en, fr, de, lb)"
|
||||
)
|
||||
@@ -222,11 +221,10 @@ class UserContext(BaseModel):
|
||||
id: int
|
||||
email: str
|
||||
username: str
|
||||
role: str # "admin" or "store"
|
||||
role: str # super_admin, platform_admin, merchant_owner, or store_member
|
||||
is_active: bool = True
|
||||
|
||||
# Admin-specific fields
|
||||
is_super_admin: bool = False
|
||||
accessible_platform_ids: list[int] | None = None # None = all platforms (super admin)
|
||||
|
||||
# Admin platform context (from JWT token after platform selection)
|
||||
@@ -253,14 +251,19 @@ class UserContext(BaseModel):
|
||||
return self.username
|
||||
|
||||
@property
|
||||
def is_admin(self) -> bool:
|
||||
"""Check if user is a platform admin."""
|
||||
return self.role == "admin"
|
||||
def is_super_admin(self) -> bool:
|
||||
"""Check if user is a super admin."""
|
||||
return self.role == "super_admin"
|
||||
|
||||
@property
|
||||
def is_store(self) -> bool:
|
||||
"""Check if user is a store."""
|
||||
return self.role == "store"
|
||||
def is_admin(self) -> bool:
|
||||
"""Check if user is an admin (super_admin or platform_admin)."""
|
||||
return self.role in ("super_admin", "platform_admin")
|
||||
|
||||
@property
|
||||
def is_store_user(self) -> bool:
|
||||
"""Check if user is a store user (merchant_owner or store_member)."""
|
||||
return self.role in ("merchant_owner", "store_member")
|
||||
|
||||
def can_access_platform(self, platform_id: int) -> bool:
|
||||
"""
|
||||
@@ -302,15 +305,14 @@ class UserContext(BaseModel):
|
||||
"username": user.username,
|
||||
"role": user.role,
|
||||
"is_active": user.is_active,
|
||||
"is_super_admin": getattr(user, "is_super_admin", False),
|
||||
"first_name": getattr(user, "first_name", None),
|
||||
"last_name": getattr(user, "last_name", None),
|
||||
"preferred_language": getattr(user, "preferred_language", None),
|
||||
}
|
||||
|
||||
# Add admin platform access info
|
||||
if user.role == "admin":
|
||||
if getattr(user, "is_super_admin", False):
|
||||
if user.is_admin:
|
||||
if user.is_super_admin:
|
||||
data["accessible_platform_ids"] = None # All platforms
|
||||
else:
|
||||
# Get platform IDs from admin_platforms relationship
|
||||
|
||||
Reference in New Issue
Block a user