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:
@@ -155,23 +155,36 @@ StorePermissions.IMPORTS_CANCEL
|
||||
|
||||
---
|
||||
|
||||
## User Role Properties
|
||||
|
||||
```python
|
||||
# Check if super admin (computed: role == "super_admin")
|
||||
user.is_super_admin # bool
|
||||
|
||||
# Check if any admin (computed: role in ("super_admin", "platform_admin"))
|
||||
user.is_admin # bool
|
||||
|
||||
# Check if platform admin (computed: role == "platform_admin")
|
||||
user.is_platform_admin # bool
|
||||
|
||||
# Check if merchant owner (computed: role == "merchant_owner")
|
||||
user.is_merchant_owner # bool
|
||||
|
||||
# Check if store-level user (computed: role in ("merchant_owner", "store_member"))
|
||||
user.is_store_user # bool
|
||||
```
|
||||
|
||||
## User Helper Methods
|
||||
|
||||
```python
|
||||
# Check if admin
|
||||
user.is_admin # bool
|
||||
|
||||
# Check if store
|
||||
user.is_store # bool
|
||||
|
||||
# Check store ownership
|
||||
# Check store ownership (via Merchant.owner_user_id)
|
||||
user.is_owner_of(store_id) # bool
|
||||
|
||||
# Check store membership
|
||||
user.is_member_of(store_id) # bool
|
||||
|
||||
# Get role in store
|
||||
user.get_store_role(store_id) # str: "owner" | "member" | None
|
||||
user.get_store_role(store_id) # str: "owner" | role name | None
|
||||
|
||||
# Check specific permission
|
||||
user.has_store_permission(store_id, "products.create") # bool
|
||||
@@ -182,7 +195,7 @@ user.has_store_permission(store_id, "products.create") # bool
|
||||
## StoreUser Helper Methods
|
||||
|
||||
```python
|
||||
# Check if owner
|
||||
# Check if owner (derived from User.role and Merchant.owner_user_id)
|
||||
store_user.is_owner # bool
|
||||
|
||||
# Check if team member
|
||||
@@ -331,7 +344,8 @@ async function getPermissions() {
|
||||
### Unit Test
|
||||
```python
|
||||
def test_owner_has_all_permissions():
|
||||
store_user = create_store_user(user_type="owner")
|
||||
user = create_user(role="merchant_owner")
|
||||
store_user = create_store_user(user=user, store=store)
|
||||
assert store_user.has_permission("products.create")
|
||||
assert store_user.has_permission("team.invite")
|
||||
```
|
||||
@@ -423,8 +437,9 @@ token = "eyJ0eXAi..."
|
||||
decoded = jwt.decode(token, verify=False)
|
||||
print(f"User ID: {decoded['sub']}")
|
||||
print(f"Username: {decoded['username']}")
|
||||
print(f"Role: {decoded['role']}")
|
||||
print(f"Role: {decoded['role']}") # super_admin, platform_admin, merchant_owner, or store_member
|
||||
print(f"Expires: {decoded['exp']}")
|
||||
# Note: is_super_admin is no longer in JWT tokens; derive from role == "super_admin"
|
||||
```
|
||||
|
||||
### Check Cookie
|
||||
|
||||
Reference in New Issue
Block a user