767 lines
27 KiB
Python
767 lines
27 KiB
Python
from django.shortcuts import render, redirect, get_object_or_404
|
|
from django.http import JsonResponse, HttpResponse
|
|
from django.contrib.auth.decorators import login_required
|
|
from django.contrib import messages
|
|
from django.db.models import Count, Q, Avg
|
|
from django.utils import timezone
|
|
from datetime import timedelta
|
|
from django.conf import settings
|
|
from app.models import (
|
|
Student,
|
|
Course,
|
|
CourseTracking,
|
|
StudentLeave,
|
|
StaffLeave,
|
|
Attendance,
|
|
AttendanceRecord,
|
|
StudentFeedback,
|
|
Routine,
|
|
Staff,
|
|
Notice,
|
|
Institute,
|
|
InstituteFeedback,
|
|
Subject,
|
|
Batch,
|
|
ParentFeedback,
|
|
Parent,
|
|
StaffInstituteFeedback,
|
|
ParentInstituteFeedback,
|
|
TeacherParentMeeting,
|
|
)
|
|
from django.views.decorators.http import require_http_methods, require_GET, require_POST
|
|
from django.core.files.storage import default_storage
|
|
from django.core.files.base import ContentFile
|
|
import json
|
|
from app.admin import custom_admin_site
|
|
import os
|
|
from django.db.models.base import transaction
|
|
from dotenv import load_dotenv
|
|
from app.firebase import save_fcm_token, FCMDevice
|
|
from django.views.static import serve
|
|
|
|
# Import views from studentviews.py
|
|
from app.studentviews import (
|
|
studentDashboard,
|
|
request_leave,
|
|
submit_feedback,
|
|
submit_institute_feedback,
|
|
get_subject_files,
|
|
)
|
|
|
|
# Import views from staffviews.py
|
|
from app.staffviews import (
|
|
teacherDashboard,
|
|
request_staff_leave,
|
|
submit_staff_institute_feedback,
|
|
save_attendance,
|
|
get_subject_schedule,
|
|
teacher_update_profile_picture,
|
|
teacher_change_password,
|
|
)
|
|
|
|
from django.contrib.auth.hashers import check_password
|
|
from django.urls import reverse
|
|
|
|
# Load environment variables
|
|
load_dotenv()
|
|
|
|
# Create your views here.
|
|
|
|
|
|
@login_required
|
|
def dashboard(request):
|
|
"""Main dashboard view that redirects to appropriate dashboard based on user role.
|
|
|
|
Args:
|
|
request: HttpRequest object containing user information
|
|
|
|
Returns:
|
|
HttpResponse: Redirects to appropriate dashboard or renders admin dashboard
|
|
"""
|
|
user = request.user
|
|
user_groups = user.groups.values_list("name", flat=True)
|
|
|
|
# Redirect based on user role
|
|
if "Student" in user_groups:
|
|
return redirect("studentDashboard")
|
|
elif "Teacher" in user_groups:
|
|
return redirect("teacherDashboard")
|
|
elif "Parent" in user_groups:
|
|
return redirect("parentDashboard")
|
|
elif "Admission Officer" in user_groups:
|
|
return redirect("admissionOfficerDashboard")
|
|
elif "HOD" in user_groups:
|
|
return redirect("hodDashboard")
|
|
else:
|
|
# Get current date and date ranges
|
|
today = timezone.now().date()
|
|
last_week = timezone.now() - timedelta(days=7)
|
|
last_month = timezone.now() - timedelta(days=30)
|
|
|
|
# Student Statistics
|
|
total_students = Student.objects.count()
|
|
active_students = Student.objects.filter(status="Active").count()
|
|
male_students = Student.objects.filter(gender="Male").count()
|
|
female_students = Student.objects.filter(gender="Female").count()
|
|
inactive_students = total_students - active_students
|
|
|
|
# Staff Statistics
|
|
total_staff = Staff.objects.count()
|
|
active_staff = Staff.objects.filter(is_active=True).count()
|
|
total_teachers = Staff.objects.filter(designation="Teacher").count()
|
|
non_teaching_staff = total_staff - total_teachers
|
|
inactive_staff = total_staff - active_staff
|
|
|
|
# Parent Statistics
|
|
total_parents = Parent.objects.count()
|
|
active_parents = Parent.objects.filter(is_active=True).count()
|
|
parents_with_students = (
|
|
Parent.objects.filter(students__isnull=False).distinct().count()
|
|
)
|
|
parents_with_multiple_students = (
|
|
Parent.objects.annotate(student_count=Count("students"))
|
|
.filter(student_count__gt=1)
|
|
.count()
|
|
)
|
|
inactive_parents = total_parents - active_parents
|
|
|
|
# Course Statistics
|
|
total_courses = Course.objects.count()
|
|
active_courses = (
|
|
Course.objects.filter(
|
|
student_trackings__progress_status__in=["Not Started", "In Progress"]
|
|
)
|
|
.distinct()
|
|
.count()
|
|
)
|
|
total_subjects = Subject.objects.count()
|
|
total_batches = Batch.objects.count()
|
|
inactive_courses = total_courses - active_courses
|
|
|
|
# Recent Activities
|
|
recent_notices = Notice.objects.all().order_by("-created_at")[:5]
|
|
recent_feedback = (
|
|
list(InstituteFeedback.objects.all().order_by("-created_at")[:5])
|
|
+ list(StaffInstituteFeedback.objects.all().order_by("-created_at")[:5])
|
|
+ list(ParentInstituteFeedback.objects.all().order_by("-created_at")[:5])
|
|
)
|
|
recent_feedback = sorted(
|
|
recent_feedback, key=lambda x: x.created_at, reverse=True
|
|
)[:5]
|
|
|
|
# Leave Requests
|
|
staff_leaves = StaffLeave.objects.filter(status=0).order_by("-created_at")[
|
|
:5
|
|
] # 0 = Pending
|
|
student_leaves = StudentLeave.objects.filter(status=0).order_by("-created_at")[
|
|
:5
|
|
] # 0 = Pending
|
|
|
|
# Teacher Rating Statistics
|
|
teacher_ratings = (
|
|
Staff.objects.filter(designation="Teacher")
|
|
.annotate(
|
|
avg_student_rating=Avg("feedbacks__rating"),
|
|
avg_parent_rating=Avg("parent_feedbacks__rating"),
|
|
total_feedbacks=Count("feedbacks") + Count("parent_feedbacks"),
|
|
)
|
|
.order_by("-avg_student_rating")[:5]
|
|
)
|
|
|
|
# Get all meetings
|
|
meetings = TeacherParentMeeting.objects.all().order_by(
|
|
"-meeting_date", "-meeting_time"
|
|
)
|
|
|
|
context = {
|
|
"title": "Dashboard",
|
|
**custom_admin_site.each_context(request),
|
|
"total_students": total_students,
|
|
"active_students": active_students,
|
|
"male_students": male_students,
|
|
"female_students": female_students,
|
|
"inactive_students": inactive_students,
|
|
"total_staff": total_staff,
|
|
"active_staff": active_staff,
|
|
"total_teachers": total_teachers,
|
|
"non_teaching_staff": non_teaching_staff,
|
|
"inactive_staff": inactive_staff,
|
|
"total_parents": total_parents,
|
|
"active_parents": active_parents,
|
|
"parents_with_students": parents_with_students,
|
|
"parents_with_multiple_students": parents_with_multiple_students,
|
|
"inactive_parents": inactive_parents,
|
|
"total_courses": total_courses,
|
|
"active_courses": active_courses,
|
|
"total_subjects": total_subjects,
|
|
"total_batches": total_batches,
|
|
"inactive_courses": inactive_courses,
|
|
"recent_notices": recent_notices,
|
|
"recent_feedback": recent_feedback,
|
|
"staff_leaves": staff_leaves,
|
|
"student_leaves": student_leaves,
|
|
"teacher_ratings": teacher_ratings,
|
|
"meetings": meetings,
|
|
}
|
|
|
|
return render(request, "admin/dashboard.html", context)
|
|
|
|
|
|
@login_required
|
|
def update_profile(request):
|
|
"""Update user profile picture based on user role.
|
|
|
|
Args:
|
|
request: HttpRequest object containing user information and uploaded file
|
|
|
|
Returns:
|
|
HttpResponse: Redirects to appropriate dashboard with success/error message
|
|
"""
|
|
if request.method == "POST":
|
|
user = request.user
|
|
user_groups = user.groups.values_list("name", flat=True)
|
|
|
|
# Handle profile image update
|
|
if "profile_image" in request.FILES:
|
|
try:
|
|
image = request.FILES["profile_image"]
|
|
|
|
# Validate image file type
|
|
allowed_types = ["image/jpeg", "image/png", "image/gif"]
|
|
if image.content_type not in allowed_types:
|
|
messages.error(
|
|
request,
|
|
"Invalid file type. Please upload a JPEG, PNG, or GIF image.",
|
|
)
|
|
return redirect("dashboard")
|
|
|
|
# Validate image size (max 5MB)
|
|
if image.size > 5 * 1024 * 1024:
|
|
messages.error(
|
|
request,
|
|
"Image size too large. Please upload an image smaller than 5MB.",
|
|
)
|
|
return redirect("dashboard")
|
|
|
|
if "Student" in user_groups:
|
|
student = Student.objects.get(id=user.id)
|
|
if student.image:
|
|
# Delete old image if updating
|
|
if os.path.isfile(student.image.path):
|
|
os.remove(student.image.path)
|
|
# Save new image
|
|
student.image = image
|
|
student.save()
|
|
messages.success(request, "Profile picture updated successfully.")
|
|
|
|
elif "Teacher" in user_groups:
|
|
staff = Staff.objects.get(id=user.id)
|
|
if staff.image:
|
|
# Delete old image if updating
|
|
if os.path.isfile(staff.image.path):
|
|
os.remove(staff.image.path)
|
|
# Save new image
|
|
staff.image = image
|
|
staff.save()
|
|
messages.success(request, "Profile picture updated successfully.")
|
|
|
|
elif "Parent" in user_groups:
|
|
parent = Parent.objects.get(id=user.id)
|
|
if parent.image:
|
|
# Delete old image if updating
|
|
if os.path.isfile(parent.image.path):
|
|
os.remove(parent.image.path)
|
|
# Save new image
|
|
parent.image = image
|
|
parent.save()
|
|
messages.success(request, "Profile picture updated successfully.")
|
|
|
|
elif "HOD" in user_groups or any(
|
|
group.lower().startswith("hod") for group in user_groups
|
|
):
|
|
# HOD is typically a Staff member with special privileges
|
|
staff = Staff.objects.get(id=user.id)
|
|
if staff.image:
|
|
# Delete old image if updating
|
|
if os.path.isfile(staff.image.path):
|
|
os.remove(staff.image.path)
|
|
# Save new image
|
|
staff.image = image
|
|
staff.save()
|
|
messages.success(request, "Profile picture updated successfully.")
|
|
|
|
else:
|
|
messages.error(
|
|
request,
|
|
"User profile not found. Please make sure you are logged in as a student, staff, or parent member.",
|
|
)
|
|
return redirect("dashboard")
|
|
|
|
except (Student.DoesNotExist, Staff.DoesNotExist, Parent.DoesNotExist) as e:
|
|
messages.error(request, "User profile not found in the database.")
|
|
return redirect("dashboard")
|
|
except Exception as e:
|
|
messages.error(request, f"Error updating profile picture: {str(e)}")
|
|
return redirect("dashboard")
|
|
else:
|
|
messages.error(request, "No profile picture uploaded.")
|
|
return redirect("dashboard")
|
|
|
|
# Redirect based on user type
|
|
if "Student" in user_groups:
|
|
return redirect("studentDashboard")
|
|
elif "Teacher" in user_groups:
|
|
return redirect("teacherDashboard")
|
|
elif "Parent" in user_groups:
|
|
return redirect("parentDashboard")
|
|
elif "Admission Officer" in user_groups:
|
|
return redirect("admissionOfficerDashboard")
|
|
elif "HOD" in user_groups:
|
|
return redirect("hodDashboard")
|
|
else:
|
|
return redirect("dashboard")
|
|
|
|
return redirect("dashboard")
|
|
|
|
|
|
@login_required
|
|
def change_password(request):
|
|
if request.method == "POST":
|
|
user = request.user
|
|
user_groups = user.groups.values_list("name", flat=True)
|
|
current_password = request.POST.get("current_password")
|
|
new_password = request.POST.get("new_password")
|
|
confirm_password = request.POST.get("confirm_password")
|
|
|
|
# Check if this is an AJAX request
|
|
is_ajax = request.headers.get("X-Requested-With") == "XMLHttpRequest"
|
|
|
|
# Determine redirect URL based on user role
|
|
redirect_url = "dashboard"
|
|
if "Student" in user_groups:
|
|
redirect_url = "studentDashboard"
|
|
elif "Teacher" in user_groups:
|
|
redirect_url = "teacherDashboard"
|
|
elif "Parent" in user_groups:
|
|
redirect_url = "parentDashboard"
|
|
elif "Admission Officer" in user_groups:
|
|
redirect_url = "admissionOfficerDashboard"
|
|
elif "HOD" in user_groups:
|
|
redirect_url = "hodDashboard"
|
|
|
|
# Validate input
|
|
if not all([current_password, new_password, confirm_password]):
|
|
if is_ajax:
|
|
return JsonResponse(
|
|
{"success": False, "error": "All password fields are required."}
|
|
)
|
|
messages.error(request, "All password fields are required.")
|
|
return redirect(redirect_url)
|
|
|
|
if new_password != confirm_password:
|
|
if is_ajax:
|
|
return JsonResponse(
|
|
{"success": False, "error": "New passwords do not match."}
|
|
)
|
|
messages.error(request, "New passwords do not match.")
|
|
return redirect(redirect_url)
|
|
|
|
# Check current password
|
|
if not user.check_password(current_password):
|
|
if is_ajax:
|
|
return JsonResponse(
|
|
{"success": False, "error": "Current password is incorrect."}
|
|
)
|
|
messages.error(request, "Current password is incorrect.")
|
|
return redirect(redirect_url)
|
|
|
|
# Set new password
|
|
try:
|
|
user.set_password(new_password)
|
|
user.save()
|
|
|
|
# For both AJAX and regular requests, we'll return success and indicate need for logout
|
|
if is_ajax:
|
|
return JsonResponse(
|
|
{
|
|
"success": True,
|
|
"redirect": "/login/",
|
|
"message": "Password changed successfully. Please login again.",
|
|
}
|
|
)
|
|
|
|
messages.success(
|
|
request, "Password changed successfully. Please login again."
|
|
)
|
|
return redirect("login")
|
|
|
|
except Exception as e:
|
|
if is_ajax:
|
|
return JsonResponse(
|
|
{"success": False, "error": f"Error changing password: {str(e)}"}
|
|
)
|
|
messages.error(request, f"Error changing password: {str(e)}")
|
|
return redirect(redirect_url)
|
|
|
|
return redirect("dashboard")
|
|
|
|
|
|
@login_required
|
|
@require_GET
|
|
def get_subjects(request):
|
|
"""Get subjects for a course and period"""
|
|
course_id = request.GET.get("course_id")
|
|
period = request.GET.get("period", 1)
|
|
|
|
if not course_id:
|
|
return JsonResponse({"success": False, "message": "Course ID is required"})
|
|
|
|
try:
|
|
subjects = Subject.objects.filter(
|
|
course_id=course_id, period_or_year=period
|
|
).values("id", "name")
|
|
|
|
return JsonResponse({"success": True, "subjects": list(subjects)})
|
|
except Exception as e:
|
|
return JsonResponse({"success": False, "message": str(e)})
|
|
|
|
|
|
@login_required
|
|
@require_GET
|
|
def get_teachers(request):
|
|
"""Get teachers for the institute"""
|
|
try:
|
|
teachers = Staff.objects.filter(
|
|
Q(designation__icontains="Teacher")
|
|
| Q(designation__icontains="Staff")
|
|
| Q(designation__icontains="Principal")
|
|
| Q(designation__icontains="HOD")
|
|
| Q(designation__icontains="Admission Officer")
|
|
| Q(designation__isnull=True)
|
|
| Q(designation="")
|
|
).values("id", "name")
|
|
|
|
return JsonResponse({"success": True, "teachers": list(teachers)})
|
|
except Exception as e:
|
|
return JsonResponse({"success": False, "message": str(e)})
|
|
|
|
|
|
@login_required
|
|
@require_GET
|
|
def get_course_duration(request):
|
|
"""Get course duration details"""
|
|
course_id = request.GET.get("course_id")
|
|
|
|
if not course_id:
|
|
return JsonResponse({"success": False, "message": "Course ID is required"})
|
|
|
|
try:
|
|
course = Course.objects.get(id=course_id)
|
|
|
|
# Calculate number of semesters or years
|
|
total_periods = course.duration
|
|
if course.duration_type == "Semester":
|
|
total_periods = course.duration * 2 # 2 semesters per year
|
|
|
|
# Create a list of periods
|
|
periods = []
|
|
for i in range(1, total_periods + 1):
|
|
if course.duration_type == "Semester":
|
|
periods.append({"value": i, "label": f"Semester {i}"})
|
|
else:
|
|
periods.append({"value": i, "label": f"Year {i}"})
|
|
|
|
return JsonResponse(
|
|
{
|
|
"success": True,
|
|
"course": {
|
|
"id": course.id,
|
|
"name": course.name,
|
|
"duration": course.duration,
|
|
"duration_type": course.duration_type,
|
|
"total_periods": total_periods,
|
|
"periods": periods,
|
|
},
|
|
}
|
|
)
|
|
except Course.DoesNotExist:
|
|
return JsonResponse({"success": False, "message": "Course not found"})
|
|
except Exception as e:
|
|
return JsonResponse({"success": False, "message": str(e)})
|
|
|
|
|
|
@login_required
|
|
def approve_student_leave(request, leave_id):
|
|
"""View to approve a student leave request"""
|
|
if request.method == "POST":
|
|
leave = get_object_or_404(StudentLeave, id=leave_id)
|
|
leave.status = 1 # Approved
|
|
leave.save()
|
|
messages.success(
|
|
request, f"Leave request for {leave.student.name} has been approved."
|
|
)
|
|
return redirect("dashboard")
|
|
|
|
|
|
@login_required
|
|
def reject_student_leave(request, leave_id):
|
|
"""View to reject a student leave request"""
|
|
if request.method == "POST":
|
|
leave = get_object_or_404(StudentLeave, id=leave_id)
|
|
leave.status = 2 # Rejected
|
|
leave.save()
|
|
messages.warning(
|
|
request, f"Leave request for {leave.student.name} has been rejected."
|
|
)
|
|
return redirect("dashboard")
|
|
|
|
|
|
@login_required
|
|
def approve_staff_leave(request, leave_id):
|
|
"""View to approve a staff leave request"""
|
|
if request.method == "POST":
|
|
leave = get_object_or_404(StaffLeave, id=leave_id)
|
|
leave.status = 1 # Approved
|
|
leave.save()
|
|
messages.success(
|
|
request, f"Leave request for {leave.staff.name} has been approved."
|
|
)
|
|
return redirect("dashboard")
|
|
|
|
|
|
@login_required
|
|
def reject_staff_leave(request, leave_id):
|
|
"""View to reject a staff leave request"""
|
|
if request.method == "POST":
|
|
leave = get_object_or_404(StaffLeave, id=leave_id)
|
|
leave.status = 2 # Rejected
|
|
leave.save()
|
|
messages.warning(
|
|
request, f"Leave request for {leave.staff.name} has been rejected."
|
|
)
|
|
return redirect("dashboard")
|
|
|
|
|
|
@login_required
|
|
def add_notice(request):
|
|
if request.method == "POST":
|
|
try:
|
|
title = request.POST.get("title")
|
|
message = request.POST.get("message")
|
|
image = request.FILES.get("image")
|
|
|
|
if not title or not message:
|
|
return JsonResponse(
|
|
{"success": False, "error": "Title and message are required"}
|
|
)
|
|
|
|
notice = Notice.objects.create(title=title, message=message, image=image)
|
|
|
|
return JsonResponse(
|
|
{"success": True, "message": "Notice added successfully"}
|
|
)
|
|
|
|
except Exception as e:
|
|
return JsonResponse({"success": False, "error": str(e)})
|
|
|
|
return JsonResponse({"success": False, "error": "Invalid request method"})
|
|
|
|
|
|
@login_required
|
|
def delete_notice(request, notice_id):
|
|
if request.method == "POST":
|
|
try:
|
|
notice = Notice.objects.get(id=notice_id)
|
|
notice.delete()
|
|
return JsonResponse({"success": True})
|
|
except Notice.DoesNotExist:
|
|
return JsonResponse({"success": False, "error": "Notice not found"})
|
|
|
|
return JsonResponse({"success": False, "error": "Invalid request method"})
|
|
|
|
|
|
@login_required
|
|
@require_POST
|
|
def save_fcm_token(request):
|
|
try:
|
|
print("Received FCM token save request")
|
|
data = json.loads(request.body)
|
|
token = data.get("token")
|
|
timestamp = data.get("timestamp")
|
|
vapid_key_used = data.get("vapidKeyUsed", False)
|
|
|
|
# Log additional information for debugging
|
|
auth_header = request.headers.get("Authorization", "")
|
|
using_vapid_auth = auth_header.startswith("VAPID ")
|
|
|
|
print(f"Auth method: {'VAPID' if using_vapid_auth else 'Cookie-based'}")
|
|
print(f"VAPID key used for token generation: {vapid_key_used}")
|
|
|
|
if not token:
|
|
print("No token provided in request")
|
|
return JsonResponse({"error": "Token is required"}, status=400)
|
|
|
|
user = request.user
|
|
print(f"User authenticated: {user.id} ({user.username})")
|
|
user_groups = user.groups.values_list("name", flat=True)
|
|
|
|
print(f"FCM token saving for user: {user.id}, groups: {list(user_groups)}")
|
|
|
|
# Determine user type based on group membership
|
|
user_type = "unknown"
|
|
if user.is_superuser:
|
|
user_type = "admin"
|
|
elif "Student" in user_groups:
|
|
user_type = "student"
|
|
elif "Teacher" in user_groups:
|
|
user_type = "teacher"
|
|
elif "Parent" in user_groups:
|
|
user_type = "parent"
|
|
|
|
# Save token directly to the user model
|
|
user.fcm_token = token
|
|
user.save(update_fields=["fcm_token"])
|
|
print(f"FCM token saved directly to user {user.name}")
|
|
|
|
# Update or create FCMDevice
|
|
try:
|
|
# Check if this is a fallback token
|
|
is_fallback = token.startswith("fcm-token-") or token.startswith(
|
|
"fallback-token-"
|
|
)
|
|
|
|
# Create or update the device
|
|
device, created = FCMDevice.objects.update_or_create(
|
|
token=token,
|
|
defaults={
|
|
"is_active": True,
|
|
"is_fallback": is_fallback,
|
|
"user_type": user_type,
|
|
},
|
|
)
|
|
|
|
print(
|
|
f"FCMDevice {'created' if created else 'updated'} with ID: {device.id}, user_type: {user_type}"
|
|
)
|
|
except Exception as e:
|
|
print(f"Error creating/updating FCMDevice: {str(e)}")
|
|
raise
|
|
|
|
return JsonResponse(
|
|
{
|
|
"status": "success",
|
|
"device_id": device.id,
|
|
"created": created,
|
|
"auth_method": "vapid" if using_vapid_auth else "cookie",
|
|
"user_type": user_type,
|
|
}
|
|
)
|
|
except json.JSONDecodeError:
|
|
print("Invalid JSON in request body")
|
|
return JsonResponse({"error": "Invalid JSON"}, status=400)
|
|
except Exception as e:
|
|
print(f"Error in save_fcm_token: {str(e)}")
|
|
return JsonResponse({"error": str(e)}, status=500)
|
|
|
|
|
|
def serve_firebase_sw(request):
|
|
"""Serve the Firebase service worker file with correct content type and security headers"""
|
|
try:
|
|
# Get the path to the service worker in the static directory
|
|
sw_path = os.path.join(settings.STATICFILES_DIRS[0], "firebase-messaging-sw.js")
|
|
|
|
# If the file doesn't exist in static directory, try staticfiles
|
|
if not os.path.exists(sw_path):
|
|
sw_path = os.path.join(settings.STATIC_ROOT, "firebase-messaging-sw.js")
|
|
|
|
if not os.path.exists(sw_path):
|
|
print(f"Service worker file not found at: {sw_path}")
|
|
return HttpResponse("Service worker file not found", status=404)
|
|
|
|
with open(sw_path, "r") as f:
|
|
content = f.read()
|
|
|
|
# Create response with correct content type
|
|
response = HttpResponse(content, content_type="application/javascript")
|
|
|
|
# Set all necessary security headers for service worker
|
|
response["Service-Worker-Allowed"] = "/"
|
|
response["Cache-Control"] = "no-cache, no-store, must-revalidate"
|
|
response["Pragma"] = "no-cache"
|
|
response["Expires"] = "0"
|
|
|
|
# Set proper CORS headers for service worker
|
|
response["Access-Control-Allow-Origin"] = "*"
|
|
response["Access-Control-Allow-Methods"] = "GET, OPTIONS"
|
|
response["Access-Control-Allow-Headers"] = "Content-Type"
|
|
|
|
print(f"Serving service worker file successfully, size: {len(content)}")
|
|
return response
|
|
except Exception as e:
|
|
print(f"Error serving service worker: {str(e)}")
|
|
return HttpResponse("Internal server error", status=500)
|
|
|
|
|
|
@login_required
|
|
def check_weak_password(request):
|
|
"""Check if the current user's password is '123'"""
|
|
user = request.user
|
|
is_weak = check_password("123", user.password)
|
|
return JsonResponse({"is_weak": is_weak})
|
|
|
|
|
|
@login_required
|
|
def get_staff_leaves(request):
|
|
"""View to get staff leave requests for AJAX updates"""
|
|
staff_leaves = StaffLeave.objects.filter(status=0).order_by("-created_at")[:5]
|
|
leaves_data = []
|
|
for leave in staff_leaves:
|
|
leaves_data.append(
|
|
{
|
|
"id": leave.id,
|
|
"staff_name": leave.staff.name,
|
|
"start_date": leave.start_date.strftime("%b %d, %Y"),
|
|
"end_date": leave.end_date.strftime("%b %d, %Y"),
|
|
"message": leave.message[:50] + "..."
|
|
if len(leave.message) > 50
|
|
else leave.message,
|
|
}
|
|
)
|
|
return JsonResponse({"staff_leaves": leaves_data})
|
|
|
|
|
|
@login_required
|
|
def get_student_leaves(request):
|
|
"""View to get student leave requests for AJAX updates"""
|
|
student_leaves = StudentLeave.objects.filter(status=0).order_by("-created_at")[:5]
|
|
leaves_data = []
|
|
for leave in student_leaves:
|
|
leaves_data.append(
|
|
{
|
|
"id": leave.id,
|
|
"student_name": leave.student.name,
|
|
"start_date": leave.start_date.strftime("%b %d, %Y"),
|
|
"end_date": leave.end_date.strftime("%b %d, %Y"),
|
|
"message": leave.message[:50] + "..."
|
|
if len(leave.message) > 50
|
|
else leave.message,
|
|
}
|
|
)
|
|
return JsonResponse({"student_leaves": leaves_data})
|
|
|
|
|
|
@login_required
|
|
@require_GET
|
|
def get_meeting_cancellation_reason(request, meeting_id):
|
|
"""API endpoint to get the cancellation reason for a meeting"""
|
|
try:
|
|
meeting = get_object_or_404(TeacherParentMeeting, id=meeting_id)
|
|
|
|
if meeting.status != "cancelled":
|
|
return JsonResponse({"success": False, "error": "Meeting is not cancelled"})
|
|
|
|
return JsonResponse({"success": True, "reason": meeting.cancellation_reason})
|
|
|
|
except Exception as e:
|
|
return JsonResponse({"success": False, "error": str(e)})
|