fix: Use request.tenant for staff filtering in multi-tenant context
- UserTenantFilteredMixin now uses request.tenant (from django-tenants middleware) instead of request.user.tenant for filtering - ResourceSerializer._get_valid_user uses request.tenant for validation - Frontend useResources sends user_id instead of user field This fixes 400 errors when creating staff resources because the tenant context is now correctly derived from the subdomain being accessed. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -70,8 +70,7 @@ export const useCreateResource = () => {
|
|||||||
const backendData: any = {
|
const backendData: any = {
|
||||||
name: resourceData.name,
|
name: resourceData.name,
|
||||||
type: resourceData.type,
|
type: resourceData.type,
|
||||||
user: resourceData.userId ? parseInt(resourceData.userId) : null,
|
user_id: resourceData.userId ? parseInt(resourceData.userId) : null,
|
||||||
timezone: 'UTC', // Default timezone
|
|
||||||
};
|
};
|
||||||
|
|
||||||
if (resourceData.maxConcurrentEvents !== undefined) {
|
if (resourceData.maxConcurrentEvents !== undefined) {
|
||||||
|
|||||||
@@ -310,14 +310,21 @@ class UserTenantFilteredMixin(SandboxFilteredQuerySetMixin):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
def filter_queryset_for_tenant(self, queryset):
|
def filter_queryset_for_tenant(self, queryset):
|
||||||
"""Filter users by tenant foreign key."""
|
"""Filter users by tenant foreign key.
|
||||||
|
|
||||||
|
Uses request.tenant (from django-tenants middleware) rather than
|
||||||
|
request.user.tenant because platform-level users (owners) may have
|
||||||
|
tenant=None on their user record but still access tenant subdomains.
|
||||||
|
"""
|
||||||
queryset = super().filter_queryset_for_tenant(queryset)
|
queryset = super().filter_queryset_for_tenant(queryset)
|
||||||
|
|
||||||
user = self.request.user
|
# Use request.tenant (from middleware) - this is set based on the
|
||||||
if user.tenant:
|
# subdomain being accessed, not the user's tenant FK
|
||||||
queryset = queryset.filter(tenant=user.tenant)
|
request_tenant = getattr(self.request, 'tenant', None)
|
||||||
|
if request_tenant:
|
||||||
|
queryset = queryset.filter(tenant=request_tenant)
|
||||||
else:
|
else:
|
||||||
# User has no tenant - return empty for safety
|
# No tenant on request - return empty for safety
|
||||||
return queryset.none()
|
return queryset.none()
|
||||||
|
|
||||||
return queryset
|
return queryset
|
||||||
|
|||||||
@@ -232,26 +232,42 @@ class ResourceSerializer(serializers.ModelSerializer):
|
|||||||
because platform-level users (owners) may have tenant=None on their user record
|
because platform-level users (owners) may have tenant=None on their user record
|
||||||
but still access tenant subdomains.
|
but still access tenant subdomains.
|
||||||
"""
|
"""
|
||||||
|
import logging
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
logger.warning(f"_get_valid_user called with user_id={user_id}")
|
||||||
|
|
||||||
if not user_id:
|
if not user_id:
|
||||||
|
logger.warning("_get_valid_user: user_id is empty, returning None")
|
||||||
return None
|
return None
|
||||||
|
|
||||||
request = self.context.get('request')
|
request = self.context.get('request')
|
||||||
if not request or not request.user.is_authenticated:
|
if not request or not request.user.is_authenticated:
|
||||||
|
logger.warning(f"_get_valid_user: no request or not authenticated, returning None")
|
||||||
return None
|
return None
|
||||||
|
|
||||||
# Use request.tenant (from django-tenants middleware) - this is set based on
|
# Use request.tenant (from django-tenants middleware) - this is set based on
|
||||||
# the subdomain being accessed, not the user's tenant FK
|
# the subdomain being accessed, not the user's tenant FK
|
||||||
tenant = getattr(request, 'tenant', None)
|
tenant = getattr(request, 'tenant', None)
|
||||||
|
logger.warning(f"_get_valid_user: request.tenant={tenant}, request.user={request.user}, request.user.tenant={getattr(request.user, 'tenant', 'N/A')}")
|
||||||
|
|
||||||
if not tenant:
|
if not tenant:
|
||||||
|
logger.warning("_get_valid_user: no tenant on request, returning None")
|
||||||
return None
|
return None
|
||||||
|
|
||||||
try:
|
try:
|
||||||
user = User.objects.get(id=user_id)
|
user = User.objects.get(id=user_id)
|
||||||
|
logger.warning(f"_get_valid_user: found user {user.email}, user.tenant={user.tenant}, comparing to request.tenant={tenant}")
|
||||||
|
|
||||||
# Verify user belongs to the same tenant as the request
|
# Verify user belongs to the same tenant as the request
|
||||||
if user.tenant == tenant:
|
if user.tenant == tenant:
|
||||||
|
logger.warning(f"_get_valid_user: tenant match! Returning user")
|
||||||
return user
|
return user
|
||||||
|
|
||||||
|
logger.warning(f"_get_valid_user: tenant mismatch, returning None")
|
||||||
return None
|
return None
|
||||||
except User.DoesNotExist:
|
except User.DoesNotExist:
|
||||||
|
logger.warning(f"_get_valid_user: user {user_id} not found")
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def _is_staff_type(self, resource_type=None, legacy_type=None):
|
def _is_staff_type(self, resource_type=None, legacy_type=None):
|
||||||
@@ -274,6 +290,10 @@ class ResourceSerializer(serializers.ModelSerializer):
|
|||||||
Validate that staff-type resources have a user assigned.
|
Validate that staff-type resources have a user assigned.
|
||||||
Staff resources MUST be linked to a staff member.
|
Staff resources MUST be linked to a staff member.
|
||||||
"""
|
"""
|
||||||
|
import logging
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
logger.warning(f"ResourceSerializer.validate called with attrs={attrs}")
|
||||||
|
|
||||||
user_id = attrs.get('user_id')
|
user_id = attrs.get('user_id')
|
||||||
resource_type = attrs.get('resource_type')
|
resource_type = attrs.get('resource_type')
|
||||||
legacy_type = attrs.get('type')
|
legacy_type = attrs.get('type')
|
||||||
|
|||||||
Reference in New Issue
Block a user