Files
training-software/training/serializers.py
Paperclip CTO dafbfa2bc4 feat(TRA-372): live groupcall backend — WebRTC signaling + session control
- Add Django Channels 4 + channels-redis to requirements and INSTALLED_APPS
- Upgrade ASGI config to ProtocolTypeRouter with JWT-authenticated WebSocket routing
- Add JWTAuthMiddleware for WebSocket token auth via query param
- Add CallSession, CallParticipant, CallEvent models with migration 0004
- MeetingCallConsumer: join/leave, P2P SDP/ICE relay via per-user groups,
  instructor mute/unmute/kick with DB audit and WS broadcast
- REST endpoints: GET/POST/DELETE /meetings/{id}/call/ (session lifecycle),
  POST /moderate/ (mute/unmute/kick), POST /screen-share/, GET /events/ (audit log)
- IsMeetingModerator permission (accepts training:signoff or meeting:moderate)
- Services: get_or_create_call_session, end_call_session, apply_moderation_action,
  toggle_screen_share with full CallEvent audit trail
- Integration tests covering REST lifecycle, moderation, and WebSocket signaling

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-05-18 14:12:48 +02:00

101 lines
3.6 KiB
Python

from rest_framework import serializers
from .models import (
AttendanceStatus,
CallEvent,
CallParticipant,
CallSession,
EmployeeAttendance,
Meeting,
MeetingParticipant,
SignoffDecision,
TrainerSignoff,
TrainingRecord,
)
class TrainingRecordSerializer(serializers.ModelSerializer):
class Meta:
model = TrainingRecord
fields = ["id", "enrollment", "completion_mode", "status", "online_passed_at", "completed_at", "created_at", "updated_at"]
read_only_fields = fields
class TrainerSignoffSerializer(serializers.ModelSerializer):
class Meta:
model = TrainerSignoff
fields = ["id", "training_record", "trainer", "decision", "notes", "signed_off_at"]
read_only_fields = ["id", "trainer", "signed_off_at"]
class SignoffRequestSerializer(serializers.Serializer):
decision = serializers.ChoiceField(choices=SignoffDecision.choices)
notes = serializers.CharField(allow_blank=True, default="")
class MeetingSerializer(serializers.ModelSerializer):
class Meta:
model = Meeting
fields = ["id", "title", "starts_at", "created_at", "updated_at"]
read_only_fields = ["id", "created_at", "updated_at"]
class MeetingParticipantSerializer(serializers.ModelSerializer):
attendance_session_id = serializers.UUIDField(source="attendance_session.id", read_only=True)
class Meta:
model = MeetingParticipant
fields = ["id", "meeting", "user", "attendance_status", "attendance_recorded_at", "attendance_recorded_by", "attendance_session_id", "created_at"]
read_only_fields = ["id", "attendance_status", "attendance_recorded_at", "attendance_recorded_by", "attendance_session_id", "created_at"]
class EmployeeAttendanceSerializer(serializers.ModelSerializer):
class Meta:
model = EmployeeAttendance
fields = ["id", "user", "attendance_date", "status", "meeting", "source", "updated_by", "updated_at", "created_at"]
read_only_fields = ["id", "updated_at", "created_at"]
class MeetingAttendanceRequestSerializer(serializers.Serializer):
user_id = serializers.UUIDField()
status = serializers.ChoiceField(choices=AttendanceStatus.choices)
class CallParticipantSerializer(serializers.ModelSerializer):
user_id = serializers.UUIDField(source="user.id", read_only=True)
user_name = serializers.SerializerMethodField()
class Meta:
model = CallParticipant
fields = ["id", "user_id", "user_name", "status", "is_muted", "screen_share_active", "joined_at", "left_at"]
read_only_fields = fields
def get_user_name(self, obj):
return obj.user.get_full_name() or str(obj.user)
class CallSessionSerializer(serializers.ModelSerializer):
active_participants = serializers.SerializerMethodField()
class Meta:
model = CallSession
fields = ["id", "meeting", "status", "started_by", "started_at", "ended_at", "active_participants"]
read_only_fields = fields
def get_active_participants(self, obj):
from .models import CallParticipantStatus
qs = obj.call_participants.filter(status=CallParticipantStatus.JOINED).select_related("user")
return CallParticipantSerializer(qs, many=True).data
class CallEventSerializer(serializers.ModelSerializer):
class Meta:
model = CallEvent
fields = ["id", "event_type", "actor", "target_user", "metadata", "occurred_at"]
read_only_fields = fields
class CallModerationRequestSerializer(serializers.Serializer):
action = serializers.ChoiceField(choices=["mute", "unmute", "kick"])
user_id = serializers.UUIDField()