From 875a284893848c90e9355a54a29032c7d304ddbe Mon Sep 17 00:00:00 2001 From: saani Date: Wed, 3 Dec 2025 20:10:15 +0000 Subject: [PATCH] feat: refactor AppointmentRequest methods and update serializers to include selected_slots field --- meetings/models.py | 189 ++++++++++++++++++++-------------------- meetings/serializers.py | 8 +- 2 files changed, 97 insertions(+), 100 deletions(-) diff --git a/meetings/models.py b/meetings/models.py index 0b3df0d..3b55d7b 100644 --- a/meetings/models.py +++ b/meetings/models.py @@ -649,106 +649,107 @@ class AppointmentRequest(models.Model): if commit: self.save() - def reject_appointment(self, reason='', commit=True): - self.status = 'rejected' - self.rejection_reason = reason - self.scheduled_datetime = None - self.jitsi_meet_url = None - self.jitsi_room_id = None + + def reject_appointment(self, reason='', commit=True): + self.status = 'rejected' + self.rejection_reason = reason + self.scheduled_datetime = None + self.jitsi_meet_url = None + self.jitsi_room_id = None + if commit: + self.save() + + def cancel_appointment(self, reason='', commit=True): + self.status = 'cancelled' + self.rejection_reason = reason + if commit: + self.save() + + def complete_appointment(self, commit=True): + self.status = 'completed' + if commit: + self.save() + + def start_meeting(self, commit=True): + if self.status == 'scheduled': + self.meeting_started_at = timezone.now() if commit: - self.save() + self.save(update_fields=['meeting_started_at']) - def cancel_appointment(self, reason='', commit=True): - self.status = 'cancelled' - self.rejection_reason = reason + def end_meeting(self, commit=True): + if self.meeting_started_at and not self.meeting_ended_at: + self.meeting_ended_at = timezone.now() + + if self.meeting_started_at: + duration = self.meeting_ended_at - self.meeting_started_at + self.meeting_duration_actual = int(duration.total_seconds() / 60) + if commit: - self.save() + self.save(update_fields=[ + 'meeting_ended_at', + 'meeting_duration_actual' + ]) - def complete_appointment(self, commit=True): - self.status = 'completed' - if commit: - self.save() + def can_join_meeting(self, *args, **kwargs): + if args: + user_type = args[0] + elif 'user_type' in kwargs: + user_type = kwargs['user_type'] + else: + user_type = 'participant' + + if not self.scheduled_datetime or not self.has_jitsi_meeting: + return False + + if self.status not in ['scheduled', 'in_progress']: + return False + + now = timezone.now() + meeting_start = self.scheduled_datetime + meeting_end = meeting_start + timedelta(minutes=self.scheduled_duration + 30) + + if user_type == 'moderator': + return meeting_start - timedelta(minutes=15) <= now <= meeting_end + timedelta(minutes=15) + else: + return meeting_start - timedelta(minutes=5) <= now <= meeting_end + + def get_meeting_join_info(self, user_type='participant'): + if not self.has_jitsi_meeting: + return None + + join_url = self.get_moderator_join_url() if user_type == 'moderator' else self.get_participant_join_url() + + return { + 'meeting_url': join_url, + 'room_id': self.jitsi_room_id, + 'scheduled_time': self.formatted_scheduled_datetime, + 'duration': self.meeting_duration_display, + 'password': self.jitsi_meeting_password if user_type == 'participant' else None, + 'can_join_now': self.can_join_meeting(user_type), + 'join_window_start': (self.scheduled_datetime - timedelta(minutes=15)).strftime("%I:%M %p") if user_type == 'moderator' else (self.scheduled_datetime - timedelta(minutes=5)).strftime("%I:%M %p"), + 'join_window_end': (self.scheduled_datetime + timedelta(minutes=self.scheduled_duration + 30)).strftime("%I:%M %p"), + 'status': self.get_status_display(), + } - def start_meeting(self, commit=True): - if self.status == 'scheduled': - self.meeting_started_at = timezone.now() - if commit: - self.save(update_fields=['meeting_started_at']) + def update_meeting_data(self, data): + if not isinstance(data, dict): + return + + current_data = self.jitsi_meeting_data or {} + current_data.update(data) + self.jitsi_meeting_data = current_data + self.save(update_fields=['jitsi_meeting_data']) - def end_meeting(self, commit=True): - if self.meeting_started_at and not self.meeting_ended_at: - self.meeting_ended_at = timezone.now() - - if self.meeting_started_at: - duration = self.meeting_ended_at - self.meeting_started_at - self.meeting_duration_actual = int(duration.total_seconds() / 60) - - if commit: - self.save(update_fields=[ - 'meeting_ended_at', - 'meeting_duration_actual' - ]) - - def can_join_meeting(self, *args, **kwargs): - if args: - user_type = args[0] - elif 'user_type' in kwargs: - user_type = kwargs['user_type'] - else: - user_type = 'participant' - - if not self.scheduled_datetime or not self.has_jitsi_meeting: - return False - - if self.status not in ['scheduled', 'in_progress']: - return False - - now = timezone.now() - meeting_start = self.scheduled_datetime - meeting_end = meeting_start + timedelta(minutes=self.scheduled_duration + 30) - - if user_type == 'moderator': - return meeting_start - timedelta(minutes=15) <= now <= meeting_end + timedelta(minutes=15) - else: - return meeting_start - timedelta(minutes=5) <= now <= meeting_end - - def get_meeting_join_info(self, user_type='participant'): - if not self.has_jitsi_meeting: - return None - - join_url = self.get_moderator_join_url() if user_type == 'moderator' else self.get_participant_join_url() - - return { - 'meeting_url': join_url, - 'room_id': self.jitsi_room_id, - 'scheduled_time': self.formatted_scheduled_datetime, - 'duration': self.meeting_duration_display, - 'password': self.jitsi_meeting_password if user_type == 'participant' else None, - 'can_join_now': self.can_join_meeting(user_type), - 'join_window_start': (self.scheduled_datetime - timedelta(minutes=15)).strftime("%I:%M %p") if user_type == 'moderator' else (self.scheduled_datetime - timedelta(minutes=5)).strftime("%I:%M %p"), - 'join_window_end': (self.scheduled_datetime + timedelta(minutes=self.scheduled_duration + 30)).strftime("%I:%M %p"), - 'status': self.get_status_display(), - } - - def update_meeting_data(self, data): - if not isinstance(data, dict): - return - - current_data = self.jitsi_meeting_data or {} - current_data.update(data) - self.jitsi_meeting_data = current_data - self.save(update_fields=['jitsi_meeting_data']) - - def get_meeting_analytics(self): - return { - 'scheduled_duration': self.scheduled_duration, - 'actual_duration': self.meeting_duration_actual, - 'started_at': self.meeting_started_at.isoformat() if self.meeting_started_at else None, - 'ended_at': self.meeting_ended_at.isoformat() if self.meeting_ended_at else None, - 'status': self.status, - 'punctuality': self._calculate_punctuality(), - 'efficiency': self._calculate_efficiency(), - } + def get_meeting_analytics(self): + return { + 'scheduled_duration': self.scheduled_duration, + 'actual_duration': self.meeting_duration_actual, + 'started_at': self.meeting_started_at.isoformat() if self.meeting_started_at else None, + 'ended_at': self.meeting_ended_at.isoformat() if self.meeting_ended_at else None, + 'status': self.status, + 'punctuality': self._calculate_punctuality(), + 'efficiency': self._calculate_efficiency(), + } def _calculate_punctuality(self): if not self.meeting_started_at or not self.scheduled_datetime: diff --git a/meetings/serializers.py b/meetings/serializers.py index 2bf4d78..a248824 100644 --- a/meetings/serializers.py +++ b/meetings/serializers.py @@ -79,8 +79,6 @@ class AppointmentRequestSerializer(serializers.ModelSerializer): moderator_join_url = serializers.SerializerMethodField() participant_join_url = serializers.SerializerMethodField() meeting_analytics = serializers.SerializerMethodField() - - # Add selected_slots field selected_slots = serializers.JSONField() class Meta: @@ -101,9 +99,9 @@ class AppointmentRequestSerializer(serializers.ModelSerializer): 'id', 'status', 'scheduled_datetime', 'scheduled_duration', 'rejection_reason', 'jitsi_meet_url', 'jitsi_room_id', 'created_at', 'updated_at', 'preferred_dates', 'preferred_time_slots', - 'selected_slots' # Make selected_slots read-only in this serializer + 'selected_slots' ] - + def get_can_join_meeting(self, obj): return obj.can_join_meeting('participant') @@ -234,8 +232,6 @@ class AppointmentRequestCreateSerializer(serializers.ModelSerializer): 'first_name', 'last_name', 'email', 'phone', 'reason', 'selected_slots' ] - # Remove preferred_dates and preferred_time_slots from fields list - # They will be calculated automatically def validate(self, data): selected_slots = data.get('selected_slots') -- 2.39.5