Files
plugins/openedx-tenant-api/openedx_tenant_api/serializers.py
DamarKusumo 2b7027e37d Add openedx-tenant-api plugin
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-10 08:20:57 +07:00

113 lines
4.1 KiB
Python

from rest_framework import serializers
from django.contrib.auth import get_user_model
from django.contrib.auth.password_validation import validate_password
from django.core.exceptions import ValidationError as DjangoValidationError
from eox_tenant.models import TenantConfig
User = get_user_model()
class CreateTenantSerializer(serializers.Serializer):
"""Serializer for tenant creation request."""
tenant_name = serializers.RegexField(
regex=r'^[a-z0-9-]+$',
max_length=63,
help_text="Tenant name (lowercase alphanumeric and hyphens only)"
)
platform_name = serializers.CharField(max_length=255, required=False)
theme_name = serializers.CharField(max_length=255, required=False, default='indigo')
org_filter = serializers.ListField(
child=serializers.CharField(),
required=False,
help_text="List of course organizations for this tenant"
)
# EDNX settings (all optional with sensible defaults)
ednx_tenant_restrict_users = serializers.BooleanField(
required=False,
default=True,
help_text="Restrict users to their assigned tenant (EDNX_TENANT_RESTRICT_USERS)"
)
ednx_tenant_user_filter_enabled = serializers.BooleanField(
required=False,
default=True,
help_text="Enable user filtering by tenant (EDNX_TENANT_USER_FILTER_ENABLED)"
)
ednx_use_signal = serializers.BooleanField(
required=False,
default=True,
help_text="Use signals for tenant context (EDNX_USE_SIGNAL)"
)
ednx_account_registration_sources = serializers.ListField(
child=serializers.CharField(),
required=False,
help_text="Allowed account registration sources (auto-generated from tenant domain if not provided)"
)
def validate_tenant_name(self, value):
"""Ensure tenant name doesn't use reserved words."""
reserved = ['local', 'studio', 'apps', 'meilisearch', 'www', 'api', 'admin']
if value in reserved:
raise serializers.ValidationError(f"'{value}' is a reserved name")
return value
class TenantResponseSerializer(serializers.Serializer):
"""Serializer for tenant creation response."""
status = serializers.CharField()
tenant_id = serializers.IntegerField()
tenant_name = serializers.CharField()
lms_url = serializers.CharField()
authn_url = serializers.CharField()
learner_dashboard_url = serializers.CharField()
class TenantAdminCreateSerializer(serializers.Serializer):
"""Serializer for tenant admin creation request."""
tenant_name = serializers.CharField(
max_length=63,
help_text="Tenant name (must exist)"
)
username = serializers.CharField(
max_length=150,
help_text="Username for the admin user"
)
email = serializers.EmailField(
help_text="Email address for the admin user"
)
password = serializers.CharField(
write_only=True,
help_text="Password for the admin user"
)
org_name = serializers.CharField(
max_length=255,
help_text="Organization name for role assignment"
)
def validate_tenant_name(self, value):
"""Validate that tenant exists."""
external_key = f"{value}.local.openedx.io"
if not TenantConfig.objects.filter(external_key=external_key).exists():
raise serializers.ValidationError("Tenant does not exist")
return value
def validate_username(self, value):
"""Validate username is unique."""
if User.objects.filter(username=value).exists():
raise serializers.ValidationError("Username already exists")
return value
def validate_email(self, value):
"""Validate email is unique."""
if User.objects.filter(email=value).exists():
raise serializers.ValidationError("Email already exists")
return value
def validate_password(self, value):
"""Validate password meets Django security requirements."""
try:
validate_password(value)
except DjangoValidationError as e:
raise serializers.ValidationError(list(e.messages))
return value