Compare commits
No commits in common. "f023a94893fd4fd386d86db137f3df51a31d5d17" and "340c478f26529cff9b1d59e459c85774278f115e" have entirely different histories.
f023a94893
...
340c478f26
2
Procfile
2
Procfile
@ -1,2 +0,0 @@
|
||||
release: python manage.py migrate
|
||||
web: gunicorn myproject.wsgi:application --bind 0.0.0.0:$PORT --workers 3
|
||||
@ -9,16 +9,10 @@ BASE_DIR = Path(__file__).resolve().parent.parent
|
||||
|
||||
SECRET_KEY = os.getenv('JWT_SECRET', 'django-insecure-fallback-secret-key')
|
||||
|
||||
DEBUG = os.getenv('DEBUG')
|
||||
DEBUG = os.getenv('DEBUG', 'False').lower() == 'true'
|
||||
|
||||
# Update ALLOWED_HOSTS for production
|
||||
ALLOWED_HOSTS = os.getenv('ALLOWED_HOSTS', '*').split(',')
|
||||
ALLOWED_HOSTS = ["*"]
|
||||
|
||||
# Update CORS for production
|
||||
CORS_ALLOWED_ORIGINS = os.getenv(
|
||||
'CORS_ALLOWED_ORIGINS',
|
||||
'http://localhost:3000,http://127.0.0.1:3000'
|
||||
).split(',')
|
||||
|
||||
|
||||
|
||||
@ -77,24 +71,24 @@ if not DEBUG:
|
||||
SECURE_PROXY_SSL_HEADER = ("HTTP_X_FORWARDED_PROTO", "https")
|
||||
|
||||
|
||||
DATABASES = {
|
||||
'default': {
|
||||
'ENGINE': 'django.db.backends.sqlite3',
|
||||
'NAME': BASE_DIR / 'db.sqlite3',
|
||||
}
|
||||
}
|
||||
|
||||
# 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),
|
||||
# 'ENGINE': 'django.db.backends.sqlite3',
|
||||
# 'NAME': BASE_DIR / 'db.sqlite3',
|
||||
# }
|
||||
# }
|
||||
|
||||
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')
|
||||
|
||||
|
||||
|
||||
@ -293,8 +293,7 @@ def api_root(request, format=None):
|
||||
"rejected": "Number of rejected requests",
|
||||
"completion_rate": "Percentage of requests that were scheduled"
|
||||
}
|
||||
},
|
||||
|
||||
}
|
||||
},
|
||||
"jitsi_integration": {
|
||||
"description": "Automatic Jitsi video meeting integration",
|
||||
|
||||
33
dockerfile
33
dockerfile
@ -1,35 +1,20 @@
|
||||
FROM python:3.11-slim
|
||||
FROM python:3.12-slim
|
||||
|
||||
# Set environment variables
|
||||
ENV PYTHONDONTWRITEBYTECODE=1
|
||||
ENV PYTHONUNBUFFERED=1
|
||||
|
||||
# Set work directory
|
||||
WORKDIR /app
|
||||
|
||||
# Install dependencies
|
||||
COPY requirements.txt /app/
|
||||
RUN pip install --upgrade pip && \
|
||||
pip install -r requirements.txt
|
||||
RUN apt-get update && apt-get install -y \
|
||||
build-essential \
|
||||
curl wget \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# Copy project
|
||||
COPY . /app/
|
||||
COPY requirements.txt .
|
||||
RUN pip install --no-cache-dir -r requirements.txt
|
||||
|
||||
# Collect static files
|
||||
RUN python manage.py collectstatic --noinput
|
||||
COPY . .
|
||||
|
||||
# Expose port
|
||||
EXPOSE 8000
|
||||
|
||||
# Run gunicorn
|
||||
CMD ["gunicorn", "myproject.wsgi:application", "--bind", "0.0.0.0:8000"]
|
||||
```
|
||||
|
||||
**Optional: Create `.dockerignore`:**
|
||||
```
|
||||
*.pyc
|
||||
__pycache__
|
||||
db.sqlite3
|
||||
.env
|
||||
.git
|
||||
venv/
|
||||
CMD ["bash", "-c", "python manage.py migrate && python manage.py collectstatic --noinput && python manage.py runserver 0.0.0.0:8000"]
|
||||
|
||||
@ -8,8 +8,7 @@ from .views import (
|
||||
reject_appointment,
|
||||
available_dates,
|
||||
user_appointments,
|
||||
appointment_stats,
|
||||
user_apointment_stats
|
||||
appointment_stats
|
||||
)
|
||||
|
||||
urlpatterns = [
|
||||
@ -26,5 +25,4 @@ urlpatterns = [
|
||||
path('user/appointments/', user_appointments, name='user-appointments'),
|
||||
|
||||
path('appointments/stats/', appointment_stats, name='appointment-stats'),
|
||||
path('user/appointments/stats/', user_apointment_stats, name='user-appointment-stats'),
|
||||
]
|
||||
@ -169,27 +169,3 @@ def appointment_stats(request):
|
||||
'users': users,
|
||||
'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,7 +24,6 @@ class CustomUserManager(BaseUserManager):
|
||||
extra_fields.setdefault('is_staff', True)
|
||||
extra_fields.setdefault('is_superuser', True)
|
||||
extra_fields.setdefault('is_active', True)
|
||||
extra_fields.setdefault('isVerified', True)
|
||||
if extra_fields.get('is_staff') is not True:
|
||||
raise ValueError(_('Superuser must have is_staff=True.'))
|
||||
if extra_fields.get('is_superuser') is not True:
|
||||
|
||||
Loading…
Reference in New Issue
Block a user