feature/meetings #45

Merged
Saani merged 2 commits from feature/meetings into main 2025-11-27 18:45:33 +00:00
10 changed files with 53 additions and 43 deletions

View File

@ -18,10 +18,10 @@ def api_root(request, format=None):
'methods': ['POST'], 'methods': ['POST'],
'required_fields': ['email', 'first_name', 'last_name', 'password', 'password2'], 'required_fields': ['email', 'first_name', 'last_name', 'password', 'password2'],
'example_request': { 'example_request': {
'email': 'user@example.com', 'email': 'saanii929@gmail',
'first_name': 'John', 'first_name': 'Saani',
'last_name': 'Doe', 'last_name': 'Iddi',
'phone_number': '+1234567890', 'phone_number': '+233552732025',
'password': 'SecurePassword123', 'password': 'SecurePassword123',
'password2': 'SecurePassword123' 'password2': 'SecurePassword123'
} }
@ -32,7 +32,7 @@ def api_root(request, format=None):
'methods': ['POST'], 'methods': ['POST'],
'required_fields': ['email', 'otp'], 'required_fields': ['email', 'otp'],
'example_request': { 'example_request': {
'email': 'user@example.com', 'email': 'saanii929@gmail',
'otp': '123456' 'otp': '123456'
} }
}, },
@ -42,7 +42,7 @@ def api_root(request, format=None):
'methods': ['POST'], 'methods': ['POST'],
'required_fields': ['email', 'password'], 'required_fields': ['email', 'password'],
'example_request': { 'example_request': {
'email': 'user@example.com', 'email': 'saanii929@gmail',
'password': 'SecurePassword123' 'password': 'SecurePassword123'
} }
}, },
@ -53,7 +53,7 @@ def api_root(request, format=None):
'required_fields': ['email'], 'required_fields': ['email'],
'optional_fields': ['context (registration/password_reset)'], 'optional_fields': ['context (registration/password_reset)'],
'example_request': { 'example_request': {
'email': 'user@example.com', 'email': 'saanii929@gmail',
'context': 'registration' 'context': 'registration'
} }
}, },
@ -63,7 +63,7 @@ def api_root(request, format=None):
'methods': ['POST'], 'methods': ['POST'],
'required_fields': ['email'], 'required_fields': ['email'],
'example_request': { 'example_request': {
'email': 'user@example.com' 'email': 'saanii929@gmail'
} }
}, },
'verify_password_reset_otp': { 'verify_password_reset_otp': {
@ -72,7 +72,7 @@ def api_root(request, format=None):
'methods': ['POST'], 'methods': ['POST'],
'required_fields': ['email', 'otp'], 'required_fields': ['email', 'otp'],
'example_request': { 'example_request': {
'email': 'user@example.com', 'email': 'saanii929@gmail',
'otp': '123456' 'otp': '123456'
} }
}, },
@ -82,7 +82,7 @@ def api_root(request, format=None):
'methods': ['POST'], 'methods': ['POST'],
'required_fields': ['email', 'otp', 'new_password', 'confirm_password'], 'required_fields': ['email', 'otp', 'new_password', 'confirm_password'],
'example_request': { 'example_request': {
'email': 'user@example.com', 'email': 'saanii929@gmail',
'otp': '123456', 'otp': '123456',
'new_password': 'NewSecurePassword123', 'new_password': 'NewSecurePassword123',
'confirm_password': 'NewSecurePassword123' 'confirm_password': 'NewSecurePassword123'
@ -104,9 +104,9 @@ def api_root(request, format=None):
"authentication": "Required (Authenticated users only)", "authentication": "Required (Authenticated users only)",
"required_fields": ["first_name", "last_name", "phone_number"], "required_fields": ["first_name", "last_name", "phone_number"],
"example_request": { "example_request": {
"first_name": "John", "first_name": "Saani",
"last_name": "Doe", "last_name": "Iddi",
"phone_number": "+1234567890" "phone_number": "+233552732025"
} }
}, },
"get_profile": { "get_profile": {
@ -291,8 +291,10 @@ def api_root(request, format=None):
"user_appointments": { "user_appointments": {
"description": "Get appointments for the authenticated user", "description": "Get appointments for the authenticated user",
"url": request.build_absolute_uri("/api/meetings/user/appointments/"), "url": request.build_absolute_uri("/api/meetings/user/appointments/"),
"methods": ["GET"], "methods": ["GET", "POST"],
"authentication": "Required", "authentication": "Required",
"request_fields": ["email"],
"example_request": {"email": "saanii929@gmail.com"},
"response": "List of user's appointment requests with enhanced availability data" "response": "List of user's appointment requests with enhanced availability data"
}, },
"schedule_appointment": { "schedule_appointment": {

View File

@ -232,7 +232,6 @@ class WeeklyAvailabilityView(generics.GenericAPIView):
return Response(weekly_availability) return Response(weekly_availability)
class UserAppointmentsView(generics.ListAPIView): class UserAppointmentsView(generics.ListAPIView):
permission_classes = [IsAuthenticated] permission_classes = [IsAuthenticated]
serializer_class = AppointmentRequestSerializer serializer_class = AppointmentRequestSerializer
@ -242,6 +241,26 @@ class UserAppointmentsView(generics.ListAPIView):
email=self.request.user.email email=self.request.user.email
).order_by('-created_at') ).order_by('-created_at')
def post(self, request, *args, **kwargs):
email = request.data.get('email')
if not email:
return Response(
{"error": "Email is required"},
status=status.HTTP_400_BAD_REQUEST
)
if email != request.user.email:
return Response(
{"error": "You can only view your own appointments"},
status=status.HTTP_403_FORBID_REQUEST
)
appointments = AppointmentRequest.objects.filter(email__iexact=email).order_by('-created_at')
serializer = self.get_serializer(appointments, many=True)
return Response(serializer.data)
class AppointmentStatsView(generics.GenericAPIView): class AppointmentStatsView(generics.GenericAPIView):
permission_classes = [IsAuthenticated, IsAdminUser] permission_classes = [IsAuthenticated, IsAdminUser]
@ -285,15 +304,14 @@ class UserAppointmentStatsView(generics.GenericAPIView):
status=status.HTTP_403_FORBIDDEN status=status.HTTP_403_FORBIDDEN
) )
stats = AppointmentRequest.objects.filter( appointments = AppointmentRequest.objects.filter(email__iexact=email)
email=email stats = {
).aggregate( 'total': appointments.count(),
total=Count('id'), 'pending': appointments.filter(status='pending_review').count(),
pending=Count('id', filter=Q(status='pending_review')), 'scheduled': appointments.filter(status='scheduled').count(),
scheduled=Count('id', filter=Q(status='scheduled')), 'rejected': appointments.filter(status='rejected').count(),
rejected=Count('id', filter=Q(status='rejected')), 'completed': appointments.filter(status='completed').count(),
completed=Count('id', filter=Q(status='completed')) }
)
total = stats['total'] total = stats['total']
scheduled = stats['scheduled'] scheduled = stats['scheduled']
@ -309,7 +327,6 @@ class UserAppointmentStatsView(generics.GenericAPIView):
'email': email 'email': email
}) })
class MatchingAvailabilityView(generics.GenericAPIView): class MatchingAvailabilityView(generics.GenericAPIView):
permission_classes = [IsAuthenticated] permission_classes = [IsAuthenticated]

View File

@ -286,14 +286,6 @@
<!-- Footer --> <!-- Footer -->
<div class="email-footer"> <div class="email-footer">
<div class="company-name">{{ settings.SITE_NAME|default:"Attune Heart Therapy" }}</div> <div class="company-name">{{ settings.SITE_NAME|default:"Attune Heart Therapy" }}</div>
<p class="support-info">
Need help? Contact our support team at
<a
href="mailto:hello@attunehearttherapy.com"
style="color: #fff; text-decoration: none"
>hello@attunehearttherapy.com</a
>
</p>
<p class="copyright"> <p class="copyright">
© {% now "Y" %} {{ settings.SITE_NAME|default:"Attune Heart Therapy" }}. © {% now "Y" %} {{ settings.SITE_NAME|default:"Attune Heart Therapy" }}.
All rights reserved. All rights reserved.

View File

@ -295,9 +295,9 @@
<p class="support-info"> <p class="support-info">
Need help? Contact our support team at Need help? Contact our support team at
<a <a
href="mailto:hello@attunehearttherapy.com" href="mailto:admin@attunehearttherapy.com"
style="color: #fff; text-decoration: none" style="color: #fff; text-decoration: none"
>hello@attunehearttherapy.com</a >admin@attunehearttherapy.com</a
> >
</p> </p>
<p class="copyright"> <p class="copyright">

View File

@ -274,9 +274,9 @@
<p class="support-info"> <p class="support-info">
Need help? Contact our support team at Need help? Contact our support team at
<a <a
href="mailto:{{ support_email }}" href="mailto:admin@attunehearttherapy.com"
style="color: #fff; text-decoration: none" style="color: #fff; text-decoration: none"
>hello@attunehearttherapy.com</a >admin@attunehearttherapy.com</a
> >
</p> </p>
<p class="copyright"> <p class="copyright">

View File

@ -5,7 +5,6 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{% block title %}Attune Heart Therapy{% endblock %}</title> <title>{% block title %}Attune Heart Therapy{% endblock %}</title>
<style> <style>
/* Reset styles for email compatibility */
body, table, td, div, p, a { body, table, td, div, p, a {
margin: 0; margin: 0;
padding: 0; padding: 0;

View File

@ -165,9 +165,9 @@
<p class="support-info"> <p class="support-info">
Need help? Contact our support team at Need help? Contact our support team at
<a <a
href="mailto:{{ support_email }}" href="mailto:admin@attunehearttherapy.com"
style="color: #fff; text-decoration: none" style="color: #fff; text-decoration: none"
>{{ support_email }}</a >admin@attunehearttherapy.com</a
> >
</p> </p>
<p class="copyright"> <p class="copyright">

View File

@ -156,9 +156,9 @@
<p class="support-info"> <p class="support-info">
Need help? Contact our support team at Need help? Contact our support team at
<a <a
href="mailto:{{ support_email }}" href="mailto:admin@attunehearttherapy.com"
style="color: #fff; text-decoration: none" style="color: #fff; text-decoration: none"
>{{ support_email }}</a >admin@attunehearttherapy.com</a
> >
</p> </p>
<p class="copyright"> <p class="copyright">

View File

@ -17,7 +17,7 @@ def send_otp_via_email(email, otp, user_name=None, context='registration'):
'otp': otp, 'otp': otp,
'expiry_minutes': 10, 'expiry_minutes': 10,
'company_name': 'Attune Heart Therapy', 'company_name': 'Attune Heart Therapy',
'support_email': 'hello@attunehearttherapy.com', 'support_email': 'admin@attunehearttherapy.com',
'current_year': timezone.now().year, 'current_year': timezone.now().year,
'email_context': context 'email_context': context
} }