mirror of
https://github.com/suitenumerique/meet.git
synced 2026-07-28 04:39:16 +00:00
f490b095d8
Allow passing configuration and access level when creating a room through the external API. Also add a few guardrails: * control whether public rooms are accepted on the external API * set the default access level when creating a new room Ensure the new room configuration and access level are returned by the serializer when listing rooms.
105 lines
3.7 KiB
Python
105 lines
3.7 KiB
Python
"""Serializers for the external API of the Meet core app."""
|
|
|
|
# pylint: disable=abstract-method
|
|
|
|
from django.conf import settings
|
|
|
|
from pydantic import ValidationError
|
|
from rest_framework import serializers
|
|
|
|
from core import models, utils
|
|
from core.api.serializers import BaseValidationOnlySerializer, RoomConfiguration
|
|
|
|
OAUTH2_GRANT_TYPE_CLIENT_CREDENTIALS = "client_credentials"
|
|
|
|
|
|
class ApplicationJwtSerializer(BaseValidationOnlySerializer):
|
|
"""Validate OAuth2 JWT token request data."""
|
|
|
|
client_id = serializers.CharField(write_only=True)
|
|
client_secret = serializers.CharField(write_only=True)
|
|
grant_type = serializers.ChoiceField(choices=[OAUTH2_GRANT_TYPE_CLIENT_CREDENTIALS])
|
|
scope = serializers.CharField(write_only=True)
|
|
|
|
|
|
class RoomSerializer(serializers.ModelSerializer):
|
|
"""External API serializer for room data exposed to applications.
|
|
|
|
Provides limited, safe room information for third-party integrations:
|
|
- Secure defaults for room creation (trusted access level)
|
|
- Computed fields (url, telephony) for external consumption
|
|
- Filtered data appropriate for delegation scenarios
|
|
- Tracks creation source for auditing
|
|
|
|
Intentionally exposes minimal information to external applications,
|
|
following the principle of least privilege.
|
|
"""
|
|
|
|
configuration = serializers.JSONField(required=False)
|
|
|
|
class Meta:
|
|
model = models.Room
|
|
fields = ["id", "name", "slug", "pin_code", "access_level", "configuration"]
|
|
read_only_fields = ["id", "name", "slug", "pin_code"]
|
|
|
|
def validate_configuration(self, value):
|
|
"""Validate room configuration against the RoomConfiguration schema."""
|
|
if value is None or value == {}:
|
|
return value
|
|
try:
|
|
RoomConfiguration.model_validate(value)
|
|
except ValidationError as e:
|
|
raise serializers.ValidationError(e.errors()) from e
|
|
return value
|
|
|
|
def validate_access_level(self, access_level):
|
|
"""Reject public access_level unless explicitly allowed or the default is already public."""
|
|
|
|
if settings.EXTERNAL_API_DEFAULT_ACCESS_LEVEL == models.RoomAccessLevel.PUBLIC:
|
|
return access_level
|
|
|
|
if (
|
|
access_level == models.RoomAccessLevel.PUBLIC
|
|
and not settings.EXTERNAL_API_ALLOW_PUBLIC_ACCESS
|
|
):
|
|
raise serializers.ValidationError(
|
|
"Public rooms are disabled for the external API."
|
|
)
|
|
return access_level
|
|
|
|
def to_representation(self, instance):
|
|
"""Enrich response with application-specific computed fields."""
|
|
output = super().to_representation(instance)
|
|
request = self.context.get("request")
|
|
pin_code = output.pop("pin_code", None)
|
|
|
|
if not request:
|
|
return output
|
|
|
|
# Add room URL for direct access
|
|
if settings.APPLICATION_BASE_URL:
|
|
output["url"] = f"{settings.APPLICATION_BASE_URL}/{instance.slug}"
|
|
|
|
# Add telephony information if enabled
|
|
if settings.ROOM_TELEPHONY_ENABLED:
|
|
output["telephony"] = {
|
|
"enabled": True,
|
|
"phone_number": settings.ROOM_TELEPHONY_PHONE_NUMBER,
|
|
"pin_code": pin_code,
|
|
"default_country": settings.ROOM_TELEPHONY_DEFAULT_COUNTRY,
|
|
}
|
|
|
|
return output
|
|
|
|
def create(self, validated_data):
|
|
"""Create room with secure defaults for application delegation."""
|
|
|
|
# Set secure defaults
|
|
validated_data["name"] = utils.generate_room_slug()
|
|
validated_data.setdefault(
|
|
"access_level", settings.EXTERNAL_API_DEFAULT_ACCESS_LEVEL
|
|
)
|
|
validated_data.setdefault("configuration", {})
|
|
|
|
return super().create(validated_data)
|