38146-vm/core/views.py
2026-02-04 06:16:58 +00:00

275 lines
10 KiB
Python

from django.core.exceptions import PermissionDenied
from django.shortcuts import render, redirect, get_object_or_404
from django.utils import translation
from django.conf import settings
from django.http import JsonResponse
from django.contrib.admin.views.decorators import staff_member_required
from django.contrib.auth.decorators import login_required
from django.contrib.auth import logout, login
from django.urls import reverse
from .models import Classroom, Subject, Teacher, Student, City
from .forms import StudentRegistrationForm
from .wablas import send_whatsapp_message
from .thawani import ThawaniClient
import random
import string
def index(request):
levels = Classroom.objects.prefetch_related('subjects').all()
context = {'levels': levels}
return render(request, 'core/index.html', context)
def set_language(request, lang_code):
next_url = request.GET.get('next', '/')
response = redirect(next_url)
if lang_code in [lang[0] for lang in settings.LANGUAGES]:
translation.activate(lang_code)
if hasattr(request, 'session'):
request.session['_language'] = lang_code
response.set_cookie(settings.LANGUAGE_COOKIE_NAME, lang_code)
return response
def subject_detail(request, pk):
subject = get_object_or_404(Subject, pk=pk)
return render(request, 'core/subject_detail.html', {'subject': subject})
@staff_member_required
def get_subjects_by_level(request):
level_id = request.GET.get('level_id') or request.GET.get('classroom_id')
if not level_id:
return JsonResponse([], safe=False)
subjects = Subject.objects.filter(classroom_id=level_id).values('id', 'name_en', 'name_ar')
return JsonResponse(list(subjects), safe=False)
def get_classroom_subjects(request):
classroom_id = request.GET.get('classroom_id')
if not classroom_id:
return JsonResponse([], safe=False)
subjects = Subject.objects.filter(classroom_id=classroom_id).values('id', 'name_en', 'price')
return JsonResponse(list(subjects), safe=False)
def get_cities_by_governorate(request):
governorate_id = request.GET.get('governorate_id')
if not governorate_id:
return JsonResponse([], safe=False)
cities = City.objects.filter(governorate_id=governorate_id).values('id', 'name_en', 'name_ar')
return JsonResponse(list(cities), safe=False)
def generate_otp():
return ''.join(random.choices(string.digits, k=6))
def register_student(request):
if request.method == 'POST':
form = StudentRegistrationForm(request.POST, request.FILES)
if form.is_valid():
student = form.save()
# Generate OTPs
mobile_otp = generate_otp()
email_otp = generate_otp()
student.mobile_otp_code = mobile_otp
student.email_otp_code = email_otp
student.save()
# Send OTP via WhatsApp
if student.mobile_number:
# Attempt to send WhatsApp message
# Note: This will only work if Wablas is configured in Admin
send_whatsapp_message(
student.mobile_number,
f"Your Verification Code is: {mobile_otp}"
)
# Simulate sending OTPs (Log to console)
print(f"========================================")
print(f"SIMULATED OTP SENDING:")
print(f"User: {student.user.username}")
print(f"Mobile OTP for {student.mobile_number}: {mobile_otp}")
print(f"Email OTP for {student.user.email}: {email_otp}")
print(f"========================================")
# Log the user in
login(request, student.user)
# Redirect to verification page
return redirect('verify_otp')
else:
form = StudentRegistrationForm()
return render(request, 'core/registration.html', {'form': form})
@login_required
def verify_otp(request):
try:
student = request.user.student_profile
except Student.DoesNotExist:
return redirect('index')
if student.is_mobile_verified and student.is_email_verified:
return redirect('profile')
error = None
if request.method == 'POST':
entered_mobile_otp = request.POST.get('mobile_otp')
entered_email_otp = request.POST.get('email_otp')
mobile_ok = student.is_mobile_verified
email_ok = student.is_email_verified
if not mobile_ok:
if entered_mobile_otp == student.mobile_otp_code:
student.is_mobile_verified = True
mobile_ok = True
else:
error = "Invalid Mobile OTP"
if not email_ok and (error is None or "Mobile" not in error):
if entered_email_otp == student.email_otp_code:
student.is_email_verified = True
email_ok = True
else:
error = "Invalid Email OTP"
if mobile_ok and email_ok:
student.mobile_otp_code = "" # Clear codes
student.email_otp_code = ""
student.save()
return redirect('profile')
else:
student.save() # Save partial verification if any
return render(request, 'core/verify_otp.html', {'error': error, 'student': student})
@login_required
def profile(request):
user = request.user
# Check for Teacher
if hasattr(user, 'teacher_profile'):
teacher_profile = user.teacher_profile
subjects = teacher_profile.subjects.all()
return render(request, 'core/teacher_dashboard.html', {
'teacher_profile': teacher_profile,
'subjects': subjects
})
# Check for Student
elif hasattr(user, 'student_profile'):
student_profile = user.student_profile
subscribed_subjects = student_profile.subscribed_subjects.all()
# Get available subjects (in same classroom, not yet subscribed)
available_subjects = []
if student_profile.classroom:
available_subjects = Subject.objects.filter(
classroom=student_profile.classroom
).exclude(
id__in=subscribed_subjects.values_list('id', flat=True)
)
return render(request, 'core/student_dashboard.html', {
'student_profile': student_profile,
'subscribed_subjects': subscribed_subjects,
'available_subjects': available_subjects
})
# Fallback (Superuser or Admin without profile)
else:
student_profile = None
return render(request, 'core/profile.html', {'student_profile': student_profile})
def custom_logout(request):
logout(request)
return redirect('index')
@login_required
def subscribe_subject(request, subject_id):
try:
student = request.user.student_profile
except Student.DoesNotExist:
return redirect('index')
subject = get_object_or_404(Subject, pk=subject_id)
# Check if already subscribed
if subject in student.subscribed_subjects.all():
return redirect('profile')
try:
thawani = ThawaniClient()
success_url = request.build_absolute_uri(reverse('payment_success')) + '?session_id={session_id}'
cancel_url = request.build_absolute_uri(reverse('payment_cancel'))
session = thawani.create_checkout_session(subject, request.user, success_url, cancel_url)
session_id = session.get('data', {}).get('session_id')
if not session_id:
return render(request, 'core/error.html', {'message': 'Could not create payment session.'})
return redirect(f"{thawani.checkout_base_url}/{session_id}")
except Exception as e:
print(f"Payment Error: {e}")
return render(request, 'core/error.html', {'message': f'Payment initialization failed: {str(e)}'})
@login_required
def payment_success(request):
session_id = request.GET.get('session_id')
if not session_id:
return redirect('profile')
try:
thawani = ThawaniClient()
response = thawani.get_checkout_session(session_id)
data = response.get('data', {})
payment_status = data.get('payment_status')
metadata = data.get('metadata', {})
subject_id = metadata.get('subject_id')
if payment_status == 'paid' and subject_id:
try:
student = request.user.student_profile
subject = get_object_or_404(Subject, pk=subject_id)
student.subscribed_subjects.add(subject)
except Exception:
pass # Already handled or user mismatch?
return redirect('profile')
else:
return render(request, 'core/error.html', {'message': f'Payment was not successful. Status: {payment_status}'})
except Exception as e:
print(f"Payment Verification Error: {e}")
return render(request, 'core/error.html', {'message': f'Payment verification failed: {str(e)}'})
@login_required
def payment_cancel(request):
return redirect('profile')
@login_required
def live_classroom(request, subject_id):
subject = get_object_or_404(Subject, pk=subject_id)
is_teacher = False
is_student = False
if hasattr(request.user, 'teacher_profile') and subject.teacher and subject.teacher.user == request.user:
is_teacher = True
if hasattr(request.user, 'student_profile') and request.user.student_profile.subscribed_subjects.filter(pk=subject_id).exists():
is_student = True
if not (is_teacher or is_student):
raise PermissionDenied("You are not authorized to join this class.")
# Generate Room Name
# We use a consistent room name based on Subject ID
room_name = f"EduPlatform_Live_Subject_{subject.id}"
return render(request, 'core/live_classroom.html', {
'subject': subject,
'room_name': room_name,
'user_display_name': request.user.get_full_name() or request.user.username,
'is_teacher': is_teacher
})