From ff3d135a201c62d2be0eee3a628bbea85c10660c Mon Sep 17 00:00:00 2001 From: saani Date: Sun, 7 Dec 2025 13:34:37 +0000 Subject: [PATCH] feat: update default user timezone to 'America/New_York' and add time conflict checks for scheduling appointments --- ..._alter_appointmentrequest_user_timezone.py | 18 ++++++++++ meetings/models.py | 34 +++++++++++++++---- meetings/serializers.py | 5 ++- 3 files changed, 47 insertions(+), 10 deletions(-) create mode 100644 meetings/migrations/0002_alter_appointmentrequest_user_timezone.py diff --git a/meetings/migrations/0002_alter_appointmentrequest_user_timezone.py b/meetings/migrations/0002_alter_appointmentrequest_user_timezone.py new file mode 100644 index 0000000..ab7f7f0 --- /dev/null +++ b/meetings/migrations/0002_alter_appointmentrequest_user_timezone.py @@ -0,0 +1,18 @@ +# Generated by Django 5.2.8 on 2025-12-07 12:49 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('meetings', '0001_initial'), + ] + + operations = [ + migrations.AlterField( + model_name='appointmentrequest', + name='user_timezone', + field=models.CharField(blank=True, default='America/New_York', max_length=63), + ), + ] diff --git a/meetings/models.py b/meetings/models.py index d46ebb8..e845c1b 100644 --- a/meetings/models.py +++ b/meetings/models.py @@ -12,6 +12,7 @@ import time from datetime import datetime, timedelta import jwt import json +from django.db import IntegrityError class EncryptionManager: def __init__(self): @@ -205,7 +206,7 @@ class AppointmentRequest(models.Model): ) scheduled_datetime = models.DateTimeField(null=True, blank=True) - user_timezone = models.CharField(max_length=63, default='UTC', blank=True) + user_timezone = models.CharField(max_length=63, default='America/New_York', blank=True) scheduled_duration = models.PositiveIntegerField( default=30, help_text="Duration in minutes" @@ -384,6 +385,17 @@ class AppointmentRequest(models.Model): unique_id = secrets.token_hex(4) self.jitsi_room_id = f"appointment_{str(self.id).replace('-', '')}_{timestamp}" return self.jitsi_room_id + + def _time_conflicts(self, start_dt, duration, exclude_self=False): + end_dt = start_dt + timedelta(minutes=duration) + qs = AppointmentRequest.objects.filter( + scheduled_datetime__lt=end_dt, + scheduled_datetime__gte=start_dt - timedelta(minutes=duration), + status='scheduled' + ) + if exclude_self: + qs = qs.exclude(pk=self.pk) + return qs.exists() def generate_jwt_token(self, user, user_type='participant'): @@ -635,30 +647,38 @@ class AppointmentRequest(models.Model): else: return meeting_start - timedelta(minutes=5) <= now <= meeting_end - def schedule_appointment(self, datetime_obj, moderator_user, participant_user=None, duration=60, create_meeting=True, commit=True): + def schedule_appointment(self, datetime_obj, duration=30, moderator_user=None, participant_user=None, create_meeting=True, commit=True): + + if self._time_conflicts(datetime_obj, duration, exclude_self=False): + raise IntegrityError("Time slot already booked — cannot schedule appointment at that datetime.") + self.status = 'scheduled' self.scheduled_datetime = datetime_obj self.scheduled_duration = duration self.rejection_reason = '' - + if create_meeting: self.create_jitsi_meeting( moderator_user=moderator_user, participant_user=participant_user, with_moderation=True ) - if commit: self.save() - def reschedule_appointment(self, new_datetime, new_duration, commit=True): + + def reschedule_appointment(self, new_datetime, new_duration=30, commit=True): + + if self._time_conflicts(new_datetime, new_duration, exclude_self=True): + raise IntegrityError("Time slot already booked — cannot reschedule to that datetime.") + self.status = 'scheduled' self.scheduled_datetime = new_datetime self.scheduled_duration = new_duration - self.rejection_reason = '' - if commit: self.save() + return self + def reject_appointment(self, reason='', commit=True): self.status = 'rejected' diff --git a/meetings/serializers.py b/meetings/serializers.py index dd4bece..715d3f0 100644 --- a/meetings/serializers.py +++ b/meetings/serializers.py @@ -224,7 +224,7 @@ class AppointmentRequestCreateSerializer(serializers.ModelSerializer): ) timezone = serializers.CharField( required=False, - default='UTC', + default='America/New_York', help_text="User's timezone (e.g., 'America/New_York', 'Africa/Accra')" ) @@ -236,7 +236,6 @@ class AppointmentRequestCreateSerializer(serializers.ModelSerializer): ] def validate_timezone(self, value): - """Validate that the timezone string is valid""" try: from zoneinfo import ZoneInfo ZoneInfo(value) @@ -338,7 +337,7 @@ class AppointmentScheduleSerializer(serializers.Serializer): time_slot = serializers.CharField(required=False, write_only=True) create_jitsi_meeting = serializers.BooleanField(default=True) jitsi_custom_config = serializers.JSONField(required=False, default=dict) - timezone = serializers.CharField(required=False, default='UTC') + timezone = serializers.CharField(required=False, default='America/New_York') def validate(self, data): scheduled_datetime = data.get('scheduled_datetime')