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
|
from datetime import datetime, timedelta
|
||||||
import jwt
|
import jwt
|
||||||
import json
|
import json
|
||||||
|
from django.db import IntegrityError
|
||||||
|
|
||||||
class EncryptionManager:
|
class EncryptionManager:
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
@ -205,7 +206,7 @@ class AppointmentRequest(models.Model):
|
|||||||
)
|
)
|
||||||
|
|
||||||
scheduled_datetime = models.DateTimeField(null=True, blank=True)
|
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(
|
scheduled_duration = models.PositiveIntegerField(
|
||||||
default=30,
|
default=30,
|
||||||
help_text="Duration in minutes"
|
help_text="Duration in minutes"
|
||||||
@ -385,6 +386,17 @@ class AppointmentRequest(models.Model):
|
|||||||
self.jitsi_room_id = f"appointment_{str(self.id).replace('-', '')}_{timestamp}"
|
self.jitsi_room_id = f"appointment_{str(self.id).replace('-', '')}_{timestamp}"
|
||||||
return self.jitsi_room_id
|
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'):
|
def generate_jwt_token(self, user, user_type='participant'):
|
||||||
|
|
||||||
if not self.jitsi_room_id:
|
if not self.jitsi_room_id:
|
||||||
@ -635,7 +647,11 @@ class AppointmentRequest(models.Model):
|
|||||||
else:
|
else:
|
||||||
return meeting_start - timedelta(minutes=5) <= now <= meeting_end
|
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.status = 'scheduled'
|
||||||
self.scheduled_datetime = datetime_obj
|
self.scheduled_datetime = datetime_obj
|
||||||
self.scheduled_duration = duration
|
self.scheduled_duration = duration
|
||||||
@ -647,18 +663,22 @@ class AppointmentRequest(models.Model):
|
|||||||
participant_user=participant_user,
|
participant_user=participant_user,
|
||||||
with_moderation=True
|
with_moderation=True
|
||||||
)
|
)
|
||||||
|
|
||||||
if commit:
|
if commit:
|
||||||
self.save()
|
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.status = 'scheduled'
|
||||||
self.scheduled_datetime = new_datetime
|
self.scheduled_datetime = new_datetime
|
||||||
self.scheduled_duration = new_duration
|
self.scheduled_duration = new_duration
|
||||||
self.rejection_reason = ''
|
|
||||||
|
|
||||||
if commit:
|
if commit:
|
||||||
self.save()
|
self.save()
|
||||||
|
return self
|
||||||
|
|
||||||
|
|
||||||
def reject_appointment(self, reason='', commit=True):
|
def reject_appointment(self, reason='', commit=True):
|
||||||
self.status = 'rejected'
|
self.status = 'rejected'
|
||||||
|
|||||||
@ -224,7 +224,7 @@ class AppointmentRequestCreateSerializer(serializers.ModelSerializer):
|
|||||||
)
|
)
|
||||||
timezone = serializers.CharField(
|
timezone = serializers.CharField(
|
||||||
required=False,
|
required=False,
|
||||||
default='UTC',
|
default='America/New_York',
|
||||||
help_text="User's timezone (e.g., 'America/New_York', 'Africa/Accra')"
|
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):
|
def validate_timezone(self, value):
|
||||||
"""Validate that the timezone string is valid"""
|
|
||||||
try:
|
try:
|
||||||
from zoneinfo import ZoneInfo
|
from zoneinfo import ZoneInfo
|
||||||
ZoneInfo(value)
|
ZoneInfo(value)
|
||||||
@ -338,7 +337,7 @@ class AppointmentScheduleSerializer(serializers.Serializer):
|
|||||||
time_slot = serializers.CharField(required=False, write_only=True)
|
time_slot = serializers.CharField(required=False, write_only=True)
|
||||||
create_jitsi_meeting = serializers.BooleanField(default=True)
|
create_jitsi_meeting = serializers.BooleanField(default=True)
|
||||||
jitsi_custom_config = serializers.JSONField(required=False, default=dict)
|
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):
|
def validate(self, data):
|
||||||
scheduled_datetime = data.get('scheduled_datetime')
|
scheduled_datetime = data.get('scheduled_datetime')
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user