Merge pull request '# Commit Message' (#24) from feature/meetings into main
Reviewed-on: https://gitea.blackbusinesslabs.com/ATTUNE-HEART-THERAPY/alternative-backend-service/pulls/24
This commit is contained in:
commit
f023a94893
2
Procfile
Normal file
2
Procfile
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
release: python manage.py migrate
|
||||||
|
web: gunicorn myproject.wsgi:application --bind 0.0.0.0:$PORT --workers 3
|
||||||
@ -9,10 +9,16 @@ BASE_DIR = Path(__file__).resolve().parent.parent
|
|||||||
|
|
||||||
SECRET_KEY = os.getenv('JWT_SECRET', 'django-insecure-fallback-secret-key')
|
SECRET_KEY = os.getenv('JWT_SECRET', 'django-insecure-fallback-secret-key')
|
||||||
|
|
||||||
DEBUG = os.getenv('DEBUG', 'False').lower() == 'true'
|
DEBUG = os.getenv('DEBUG')
|
||||||
|
|
||||||
ALLOWED_HOSTS = ["*"]
|
# Update ALLOWED_HOSTS for production
|
||||||
|
ALLOWED_HOSTS = os.getenv('ALLOWED_HOSTS', '*').split(',')
|
||||||
|
|
||||||
|
# Update CORS for production
|
||||||
|
CORS_ALLOWED_ORIGINS = os.getenv(
|
||||||
|
'CORS_ALLOWED_ORIGINS',
|
||||||
|
'http://localhost:3000,http://127.0.0.1:3000'
|
||||||
|
).split(',')
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -71,24 +77,24 @@ if not DEBUG:
|
|||||||
SECURE_PROXY_SSL_HEADER = ("HTTP_X_FORWARDED_PROTO", "https")
|
SECURE_PROXY_SSL_HEADER = ("HTTP_X_FORWARDED_PROTO", "https")
|
||||||
|
|
||||||
|
|
||||||
# DATABASES = {
|
|
||||||
# 'default': {
|
|
||||||
# 'ENGINE': 'django.db.backends.sqlite3',
|
|
||||||
# 'NAME': BASE_DIR / 'db.sqlite3',
|
|
||||||
# }
|
|
||||||
# }
|
|
||||||
|
|
||||||
DATABASES = {
|
DATABASES = {
|
||||||
'default': {
|
'default': {
|
||||||
'ENGINE': 'django.db.backends.postgresql',
|
'ENGINE': 'django.db.backends.sqlite3',
|
||||||
'NAME': os.getenv('POSTGRES_DB'),
|
'NAME': BASE_DIR / 'db.sqlite3',
|
||||||
'USER': os.getenv('POSTGRES_USER'),
|
|
||||||
'PASSWORD': os.getenv('POSTGRES_PASSWORD'),
|
|
||||||
'HOST': os.getenv('POSTGRES_HOST', 'postgres'),
|
|
||||||
'PORT': os.getenv('POSTGRES_PORT', 5432),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# DATABASES = {
|
||||||
|
# 'default': {
|
||||||
|
# 'ENGINE': 'django.db.backends.postgresql',
|
||||||
|
# 'NAME': os.getenv('POSTGRES_DB'),
|
||||||
|
# 'USER': os.getenv('POSTGRES_USER'),
|
||||||
|
# 'PASSWORD': os.getenv('POSTGRES_PASSWORD'),
|
||||||
|
# 'HOST': os.getenv('POSTGRES_HOST', 'postgres'),
|
||||||
|
# 'PORT': os.getenv('POSTGRES_PORT', 5432),
|
||||||
|
# }
|
||||||
|
# }
|
||||||
|
|
||||||
ENCRYPTION_KEY = os.getenv('ENCRYPTION_KEY')
|
ENCRYPTION_KEY = os.getenv('ENCRYPTION_KEY')
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -293,7 +293,8 @@ def api_root(request, format=None):
|
|||||||
"rejected": "Number of rejected requests",
|
"rejected": "Number of rejected requests",
|
||||||
"completion_rate": "Percentage of requests that were scheduled"
|
"completion_rate": "Percentage of requests that were scheduled"
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
|
||||||
},
|
},
|
||||||
"jitsi_integration": {
|
"jitsi_integration": {
|
||||||
"description": "Automatic Jitsi video meeting integration",
|
"description": "Automatic Jitsi video meeting integration",
|
||||||
|
|||||||
33
dockerfile
33
dockerfile
@ -1,20 +1,35 @@
|
|||||||
FROM python:3.12-slim
|
FROM python:3.11-slim
|
||||||
|
|
||||||
|
# Set environment variables
|
||||||
ENV PYTHONDONTWRITEBYTECODE=1
|
ENV PYTHONDONTWRITEBYTECODE=1
|
||||||
ENV PYTHONUNBUFFERED=1
|
ENV PYTHONUNBUFFERED=1
|
||||||
|
|
||||||
|
# Set work directory
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
|
||||||
RUN apt-get update && apt-get install -y \
|
# Install dependencies
|
||||||
build-essential \
|
COPY requirements.txt /app/
|
||||||
curl wget \
|
RUN pip install --upgrade pip && \
|
||||||
&& rm -rf /var/lib/apt/lists/*
|
pip install -r requirements.txt
|
||||||
|
|
||||||
COPY requirements.txt .
|
# Copy project
|
||||||
RUN pip install --no-cache-dir -r requirements.txt
|
COPY . /app/
|
||||||
|
|
||||||
COPY . .
|
# Collect static files
|
||||||
|
RUN python manage.py collectstatic --noinput
|
||||||
|
|
||||||
|
# Expose port
|
||||||
EXPOSE 8000
|
EXPOSE 8000
|
||||||
|
|
||||||
CMD ["bash", "-c", "python manage.py migrate && python manage.py collectstatic --noinput && python manage.py runserver 0.0.0.0:8000"]
|
# Run gunicorn
|
||||||
|
CMD ["gunicorn", "myproject.wsgi:application", "--bind", "0.0.0.0:8000"]
|
||||||
|
```
|
||||||
|
|
||||||
|
**Optional: Create `.dockerignore`:**
|
||||||
|
```
|
||||||
|
*.pyc
|
||||||
|
__pycache__
|
||||||
|
db.sqlite3
|
||||||
|
.env
|
||||||
|
.git
|
||||||
|
venv/
|
||||||
@ -8,7 +8,8 @@ from .views import (
|
|||||||
reject_appointment,
|
reject_appointment,
|
||||||
available_dates,
|
available_dates,
|
||||||
user_appointments,
|
user_appointments,
|
||||||
appointment_stats
|
appointment_stats,
|
||||||
|
user_apointment_stats
|
||||||
)
|
)
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
@ -25,4 +26,5 @@ urlpatterns = [
|
|||||||
path('user/appointments/', user_appointments, name='user-appointments'),
|
path('user/appointments/', user_appointments, name='user-appointments'),
|
||||||
|
|
||||||
path('appointments/stats/', appointment_stats, name='appointment-stats'),
|
path('appointments/stats/', appointment_stats, name='appointment-stats'),
|
||||||
|
path('user/appointments/stats/', user_apointment_stats, name='user-appointment-stats'),
|
||||||
]
|
]
|
||||||
@ -169,3 +169,27 @@ def appointment_stats(request):
|
|||||||
'users': users,
|
'users': users,
|
||||||
'completion_rate': round((scheduled / total * 100), 2) if total > 0 else 0
|
'completion_rate': round((scheduled / total * 100), 2) if total > 0 else 0
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@api_view(['GET'])
|
||||||
|
@permission_classes([IsAuthenticated])
|
||||||
|
def user_apointment_stats(request):
|
||||||
|
if not request.user.is_staff:
|
||||||
|
return Response(
|
||||||
|
{'error': 'Unauthorized'},
|
||||||
|
status=status.HTTP_403_FORBIDDEN
|
||||||
|
)
|
||||||
|
|
||||||
|
total = AppointmentRequest.objects.filter(email=request.user.email).count()
|
||||||
|
pending = AppointmentRequest.objects.filter(email=request.user.email, status='pending_review').count()
|
||||||
|
scheduled = AppointmentRequest.objects.filter(email=request.user.email, status='scheduled').count()
|
||||||
|
rejected = AppointmentRequest.objects.filter(email=request.user.email, status='rejected').count()
|
||||||
|
completed = AppointmentRequest.objects.filter(email=request.user.email, status='completed').count()
|
||||||
|
|
||||||
|
return Response({
|
||||||
|
'total_requests': total,
|
||||||
|
'pending_review': pending,
|
||||||
|
'scheduled': scheduled,
|
||||||
|
'rejected': rejected,
|
||||||
|
'completed': completed,
|
||||||
|
'completion_rate': round((scheduled / total * 100), 2) if total > 0 else 0
|
||||||
|
})
|
||||||
|
|||||||
@ -24,6 +24,7 @@ class CustomUserManager(BaseUserManager):
|
|||||||
extra_fields.setdefault('is_staff', True)
|
extra_fields.setdefault('is_staff', True)
|
||||||
extra_fields.setdefault('is_superuser', True)
|
extra_fields.setdefault('is_superuser', True)
|
||||||
extra_fields.setdefault('is_active', True)
|
extra_fields.setdefault('is_active', True)
|
||||||
|
extra_fields.setdefault('isVerified', True)
|
||||||
if extra_fields.get('is_staff') is not True:
|
if extra_fields.get('is_staff') is not True:
|
||||||
raise ValueError(_('Superuser must have is_staff=True.'))
|
raise ValueError(_('Superuser must have is_staff=True.'))
|
||||||
if extra_fields.get('is_superuser') is not True:
|
if extra_fields.get('is_superuser') is not True:
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user