diff --git a/meetings/migrations/0001_initial.py b/meetings/migrations/0001_initial.py new file mode 100644 index 0000000..6a17f61 --- /dev/null +++ b/meetings/migrations/0001_initial.py @@ -0,0 +1,68 @@ +# Generated by Django 5.2.8 on 2025-12-05 12:12 + +import meetings.models +import uuid +from django.db import migrations, models + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ] + + operations = [ + migrations.CreateModel( + name='AdminWeeklyAvailability', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('availability_schedule', models.JSONField(default=dict, help_text='Dictionary with days as keys and lists of time slots as values')), + ('created_at', models.DateTimeField(auto_now_add=True)), + ('updated_at', models.DateTimeField(auto_now=True)), + ], + options={ + 'verbose_name': 'Admin Weekly Availability', + 'verbose_name_plural': 'Admin Weekly Availability', + }, + ), + migrations.CreateModel( + name='AppointmentRequest', + fields=[ + ('id', models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False)), + ('first_name', models.CharField(max_length=255)), + ('last_name', models.CharField(max_length=255)), + ('email', models.EmailField(max_length=255)), + ('phone', models.CharField(blank=True, max_length=50, null=True)), + ('reason', models.TextField(blank=True, help_text='Reason for appointment', null=True)), + ('preferred_dates', models.JSONField(help_text='List of preferred dates (YYYY-MM-DD format)')), + ('preferred_time_slots', models.JSONField(help_text='List of preferred time slots (morning/afternoon/evening)')), + ('status', models.CharField(choices=[('pending_review', 'Pending Review'), ('scheduled', 'Scheduled'), ('rejected', 'Rejected'), ('completed', 'Completed'), ('cancelled', 'Cancelled')], default='pending_review', max_length=20)), + ('scheduled_datetime', models.DateTimeField(blank=True, null=True)), + ('user_timezone', models.CharField(blank=True, default='UTC', max_length=63)), + ('scheduled_duration', models.PositiveIntegerField(default=30, help_text='Duration in minutes')), + ('rejection_reason', meetings.models.EncryptedTextField(blank=True, null=True)), + ('jitsi_meet_url', models.URLField(blank=True, help_text='Jitsi Meet URL for the video session', max_length=2000, null=True, unique=True)), + ('jitsi_room_id', models.CharField(blank=True, help_text='Jitsi room ID', max_length=255, null=True, unique=True)), + ('jitsi_meeting_created', models.BooleanField(default=False)), + ('jitsi_moderator_token', models.TextField(blank=True, null=True)), + ('jitsi_participant_token', models.TextField(blank=True, null=True)), + ('jitsi_meeting_password', models.CharField(blank=True, max_length=255, null=True)), + ('jitsi_meeting_config', models.JSONField(default=dict, help_text='Jitsi meeting configuration and settings')), + ('jitsi_recording_url', models.URLField(blank=True, help_text='URL to meeting recording', null=True)), + ('jitsi_meeting_data', models.JSONField(default=dict, help_text='Additional meeting data (participants, duration, etc)')), + ('selected_slots', models.JSONField(default=list, help_text='Original selected slots with day and time slot pairs')), + ('meeting_started_at', models.DateTimeField(blank=True, null=True)), + ('meeting_ended_at', models.DateTimeField(blank=True, null=True)), + ('meeting_duration_actual', models.PositiveIntegerField(default=0, help_text='Actual meeting duration in minutes')), + ('created_at', models.DateTimeField(auto_now_add=True)), + ('updated_at', models.DateTimeField(auto_now=True)), + ], + options={ + 'verbose_name': 'Appointment Request', + 'verbose_name_plural': 'Appointment Requests', + 'ordering': ['-created_at'], + 'indexes': [models.Index(fields=['status', 'scheduled_datetime'], name='meetings_ap_status_4e4e26_idx'), models.Index(fields=['email', 'created_at'], name='meetings_ap_email_b8ed9d_idx'), models.Index(fields=['jitsi_meeting_created', 'scheduled_datetime'], name='meetings_ap_jitsi_m_f3c488_idx'), models.Index(fields=['meeting_started_at'], name='meetings_ap_meeting_157142_idx')], + }, + ), + ] diff --git a/meetings/models.py b/meetings/models.py index 498d1c8..0c4eef3 100644 --- a/meetings/models.py +++ b/meetings/models.py @@ -685,6 +685,7 @@ class AppointmentRequest(models.Model): def end_meeting(self, commit=True): if self.meeting_started_at and not self.meeting_ended_at: self.meeting_ended_at = timezone.now() + self.status = 'completed' if self.meeting_started_at: duration = self.meeting_ended_at - self.meeting_started_at diff --git a/users/migrations/0001_initial.py b/users/migrations/0001_initial.py new file mode 100644 index 0000000..cf6f651 --- /dev/null +++ b/users/migrations/0001_initial.py @@ -0,0 +1,72 @@ +# Generated by Django 5.2.8 on 2025-12-05 12:12 + +import django.db.models.deletion +from django.conf import settings +from django.db import migrations, models + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ('auth', '0012_alter_user_first_name_max_length'), + ] + + operations = [ + migrations.CreateModel( + name='ContactMessage', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name', models.CharField(max_length=255)), + ('email', models.EmailField(max_length=254)), + ('phone', models.CharField(blank=True, max_length=20)), + ('message', models.TextField()), + ('created_at', models.DateTimeField(auto_now_add=True)), + ('is_read', models.BooleanField(default=False)), + ('is_responded', models.BooleanField(default=False)), + ], + options={ + 'verbose_name': 'Contact Message', + 'verbose_name_plural': 'Contact Messages', + 'ordering': ['-created_at'], + }, + ), + migrations.CreateModel( + name='CustomUser', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('password', models.CharField(max_length=128, verbose_name='password')), + ('email', models.EmailField(max_length=254, unique=True)), + ('first_name', models.CharField(max_length=50)), + ('last_name', models.CharField(max_length=50)), + ('is_staff', models.BooleanField(default=False)), + ('is_superuser', models.BooleanField(default=False)), + ('is_active', models.BooleanField(default=True)), + ('isVerified', models.BooleanField(default=False)), + ('verify_otp', models.CharField(blank=True, max_length=6, null=True)), + ('verify_otp_expiry', models.DateTimeField(blank=True, null=True)), + ('forgot_password_otp', models.CharField(blank=True, max_length=6, null=True)), + ('forgot_password_otp_expiry', models.DateTimeField(blank=True, null=True)), + ('phone_number', models.CharField(blank=True, max_length=20)), + ('last_login', models.DateTimeField(auto_now=True)), + ('date_joined', models.DateTimeField(auto_now_add=True)), + ('groups', models.ManyToManyField(blank=True, help_text='The groups this user belongs to. A user will get all permissions granted to each of their groups.', related_name='user_set', related_query_name='user', to='auth.group', verbose_name='groups')), + ('user_permissions', models.ManyToManyField(blank=True, help_text='Specific permissions for this user.', related_name='user_set', related_query_name='user', to='auth.permission', verbose_name='user permissions')), + ], + options={ + 'abstract': False, + }, + ), + migrations.CreateModel( + name='UserProfile', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('bio', models.TextField(blank=True, max_length=500)), + ('timezone', models.CharField(default='UTC', max_length=50)), + ('created_at', models.DateTimeField(auto_now_add=True)), + ('updated_at', models.DateTimeField(auto_now=True)), + ('user', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='profile', to=settings.AUTH_USER_MODEL)), + ], + ), + ]