from rest_framework.serializers import ModelSerializer, SerializerMethodField, IntegerField from apps.orgs.models import Organization, OrganizationMembership, OrganizationInvitation, Role, RoleMembership, TrainingFile from apps.users.serializers import UserSerializer class OrganizationSerializer(ModelSerializer): owner = UserSerializer(read_only = True) member_count = SerializerMethodField() role_count = SerializerMethodField() class Meta: model = Organization fields = ['id', 'uuid', 'name', 'description', 'owner', 'created_at', 'updated_at', 'member_count', 'role_count'] read_only_fields = ['uuid', 'owner', 'created_at', 'updated_at'] def get_member_count(self, obj): return obj.memberships.count() def get_role_count(self, obj): return obj.roles.count() class OrganizationMembershipSerializer(ModelSerializer): user = UserSerializer(read_only = True) user_id = IntegerField(write_only = True, required = False) class Meta: model = OrganizationMembership fields = ['id', 'user', 'user_id', 'organization', 'created_at', 'updated_at'] read_only_fields = ['organization', 'created_at', 'updated_at'] def create(self, validated_data): user_id = validated_data.pop('user_id', None) if user_id: validated_data['user_id'] = user_id return super().create(validated_data) class OrganizationInvitationSerializer(ModelSerializer): created_by = UserSerializer(read_only = True) invite_url = SerializerMethodField() is_valid = SerializerMethodField() class Meta: model = OrganizationInvitation fields = ['id', 'token', 'organization', 'created_by', 'expires_at', 'max_uses', 'is_active', 'invite_url', 'is_valid', 'created_at', 'updated_at', 'uses'] read_only_fields = ['token', 'organization', 'created_by', 'max_uses', 'created_at', 'updated_at', 'uses'] def get_invite_url(self, obj): request = self.context.get('request') if request: return request.build_absolute_uri(f'/invite/{obj.token}') return f'/invite/{obj.token}' def get_is_valid(self, obj): return obj.is_valid() class RoleMembershipSerializer(ModelSerializer): user = UserSerializer(read_only = True) class Meta: model = RoleMembership fields = ['id', 'user', 'role', 'created_at'] read_only_fields = ['created_at'] class RoleSerializer(ModelSerializer): organization = OrganizationSerializer(read_only = True) member_count = SerializerMethodField() class Meta: model = Role fields = ['id', 'uuid', 'name', 'organization', 'member_count', 'description', 'created_at', 'updated_at'] read_only_fields = ['uuid', 'organization', 'created_at', 'updated_at'] def get_member_count(self, obj): return obj.memberships.count() class TrainingFileSerializer(ModelSerializer): uploaded_by = UserSerializer(read_only = True) file_url = SerializerMethodField() class Meta: model = TrainingFile fields = ['id', 'uuid', 'organization', 'uploaded_by', 'file', 'file_name', 'file_size', 'file_type', 'description', 'is_processed', 'file_url', 'created_at', 'updated_at'] read_only_fields = ['uuid', 'uploaded_by', 'file_size', 'file_type', 'is_processed', 'created_at', 'updated_at', 'organization'] def get_file_url(self, obj): request = self.context.get('request') if request and obj.file: return request.build_absolute_uri(obj.file.url) return None def validate_file(self, value): """Validate that uploaded file is a text-based file.""" if not value: raise ValueError('File is required') import os file_extension = os.path.splitext(value.name)[1][1:].lower() if file_extension not in TrainingFile.ALLOWED_EXTENSIONS: raise ValueError( f'File type ".{file_extension}" is not allowed. ' f'Allowed types: {", ".join(TrainingFile.ALLOWED_EXTENSIONS)}' ) max_size = 50 * 1024 * 1024 if value.size > max_size: raise ValueError(f'File size must not exceed 50MB. Current size: {value.size / 1024 / 1024:.2f}MB') return value def create(self, validated_data): file_obj = validated_data.get('file') if file_obj: validated_data['file_size'] = file_obj.size import os file_extension = os.path.splitext(file_obj.name)[1][1:].lower() validated_data['file_type'] = file_extension return super().create(validated_data)