feat: update default user timezone to 'America/New_York' and add time conflict checks for scheduling appointments #76
@ -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),
|
||||
),
|
||||
]
|
||||
@ -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'
|
||||
|
||||
@ -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')
|
||||
|
||||
Loading…
Reference in New Issue
Block a user