huge updates
This commit is contained in:
1 parent
861d64c95a
commit
ee89d38489
56 files changed
+10130
-4185
No files matched your search
+541
-336
@@ -1,11 +1,11 @@
|
||||
from app.models import FCMDevice
|
||||
from django.shortcuts import render, redirect, get_object_or_404
|
||||
from django.http import JsonResponse, HttpResponse
|
||||
from django.http import JsonResponse, HttpResponse, FileResponse
|
||||
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 .models import (
|
||||
Student,
|
||||
Course,
|
||||
@@ -24,16 +24,18 @@ from .models import (
|
||||
Batch,
|
||||
)
|
||||
from app.admin import custom_admin_site
|
||||
from django.views.decorators.http import require_http_methods, require_GET
|
||||
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
|
||||
import os
|
||||
from django.db.models.base import transaction
|
||||
from .utils import generate_otp, store_otp, verify_otp, send_otp_sms
|
||||
from .utils import generate_otp, generate_secret_key, store_secret_key, verify_otp, send_otp_sms
|
||||
from django.conf import settings
|
||||
from dotenv import load_dotenv
|
||||
|
||||
from .firebase import save_fcm_token, get_firebase_js, FCMDevice
|
||||
from django.template.loader import render_to_string
|
||||
from django.views.static import serve
|
||||
# Import views from studentviews.py
|
||||
from .studentviews import (
|
||||
studentDashboard,
|
||||
@@ -54,395 +56,373 @@ from .staffviews import (
|
||||
teacher_change_password,
|
||||
)
|
||||
|
||||
from django.contrib.auth.hashers import check_password
|
||||
|
||||
# Load environment variables
|
||||
load_dotenv()
|
||||
|
||||
# Create your views here.
|
||||
|
||||
|
||||
# FireBase
|
||||
def saveFCMToken(request, token):
|
||||
try:
|
||||
FCMDevice(token=token).save()
|
||||
except:
|
||||
pass
|
||||
return JsonResponse({})
|
||||
|
||||
|
||||
def showFirebaseJS(request):
|
||||
data = f"""
|
||||
importScripts('https://www.gstatic.com/firebasejs/11.0.2/firebase-app-compat.js');
|
||||
importScripts('https://www.gstatic.com/firebasejs/11.0.2/firebase-messaging-compat.js');
|
||||
|
||||
firebase.initializeApp({{
|
||||
apiKey: "{os.getenv('FIREBASE_API_KEY')}",
|
||||
authDomain: "{os.getenv('FIREBASE_AUTH_DOMAIN')}",
|
||||
projectId: "{os.getenv('FIREBASE_PROJECT_ID')}",
|
||||
storageBucket: "{os.getenv('FIREBASE_STORAGE_BUCKET')}",
|
||||
messagingSenderId: "{os.getenv('FIREBASE_MESSAGING_SENDER_ID')}",
|
||||
appId: "{os.getenv('FIREBASE_APP_ID')}",
|
||||
measurementId: "{os.getenv('FIREBASE_MEASUREMENT_ID')}"
|
||||
}});
|
||||
|
||||
const messaging = firebase.messaging();
|
||||
|
||||
messaging.onBackgroundMessage((payload) => {{
|
||||
const notificationTitle = payload.notification.title;
|
||||
const notificationOptions = {{
|
||||
body: payload.notification.body,
|
||||
icon: payload.notification.icon
|
||||
}};
|
||||
|
||||
return self.registration.showNotification(notificationTitle, notificationOptions);
|
||||
}});
|
||||
"""
|
||||
return HttpResponse(data, content_type="text/javascript")
|
||||
|
||||
|
||||
@login_required
|
||||
def dashboard(request):
|
||||
"""Main dashboard view that redirects to appropriate dashboard based on user role"""
|
||||
user = request.user
|
||||
user_groups = user.groups.values_list("name", flat=True)
|
||||
|
||||
|
||||
|
||||
# Redirect based on user role
|
||||
if "Student" in user_groups:
|
||||
print("Redirecting to student dashboard")
|
||||
return redirect("studentDashboard")
|
||||
elif "Teacher" in user_groups:
|
||||
print("Redirecting to teacher dashboard")
|
||||
return redirect("teacherDashboard")
|
||||
elif user.is_superuser or user.is_staff:
|
||||
# Admin users get the admin dashboard
|
||||
print("Showing admin dashboard")
|
||||
|
||||
# Get current date and date ranges
|
||||
today = timezone.now().date()
|
||||
last_week = timezone.now() - timedelta(days=7)
|
||||
last_month = timezone.now() - timedelta(days=30)
|
||||
|
||||
# Debug prints for user authentication
|
||||
print(f"Is authenticated: {request.user.is_authenticated}")
|
||||
print(f"Is staff: {request.user.is_staff}")
|
||||
print(f"Is superuser: {request.user.is_superuser}")
|
||||
print("-------------------------\n")
|
||||
|
||||
# Student Statistics - with debug prints
|
||||
total_students = Student.objects.count()
|
||||
print("\nDEBUG Student Statistics:")
|
||||
print("-------------------------")
|
||||
print(f"Total students (from count): {total_students}")
|
||||
|
||||
# Get all students and print their statuses
|
||||
all_students = Student.objects.all()
|
||||
print("\nAll students and their statuses:")
|
||||
for student in all_students:
|
||||
print(f"- {student.name}: {student.status}")
|
||||
|
||||
active_students = Student.objects.filter(status="Active").count()
|
||||
print(f"\nActive students: {active_students}")
|
||||
|
||||
completed_students = Student.objects.filter(status="Completed").count()
|
||||
print(f"Completed students: {completed_students}")
|
||||
|
||||
on_leave_students = Student.objects.filter(status="Leave").count()
|
||||
print(f"Students on leave: {on_leave_students}")
|
||||
|
||||
print(f"\nSum of status counts: {active_students + completed_students + on_leave_students}")
|
||||
print("-------------------------\n")
|
||||
|
||||
# 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()
|
||||
completed_students = Student.objects.filter(status="Completed").count()
|
||||
on_leave_students = Student.objects.filter(status="Leave").count()
|
||||
|
||||
# Staff Statistics
|
||||
total_staff = Staff.objects.count()
|
||||
active_staff = Staff.objects.filter(is_active=True).count()
|
||||
staff_on_leave = (
|
||||
Staff_leave.objects.filter(status=1).values("staff").distinct().count()
|
||||
)
|
||||
|
||||
# Course Statistics
|
||||
total_courses = Course.objects.count()
|
||||
active_courses = (
|
||||
Course.objects.filter(student_trackings__progress_status="In Progress")
|
||||
.distinct()
|
||||
.count()
|
||||
)
|
||||
completed_courses = (
|
||||
Course.objects.filter(student_trackings__progress_status="Completed")
|
||||
.distinct()
|
||||
.count()
|
||||
)
|
||||
|
||||
# Course Tracking Statistics
|
||||
course_trackings = CourseTracking.objects.all()
|
||||
in_progress_trackings = course_trackings.filter(progress_status="In Progress")
|
||||
completed_trackings = course_trackings.filter(progress_status="Completed")
|
||||
dropped_trackings = course_trackings.filter(progress_status="Dropped")
|
||||
|
||||
# Recent Leave Requests
|
||||
recent_student_leaves = Student_Leave.objects.filter(
|
||||
created_at__gte=last_week
|
||||
).order_by("-created_at")[:5]
|
||||
|
||||
recent_staff_leaves = Staff_leave.objects.filter(
|
||||
created_at__gte=last_week
|
||||
).order_by("-created_at")[:5]
|
||||
|
||||
# Pending Leave Requests
|
||||
pending_student_leaves = Student_Leave.objects.filter(status=0)
|
||||
pending_staff_leaves = Staff_leave.objects.filter(status=0).order_by("-created_at")
|
||||
|
||||
# Attendance Statistics
|
||||
today_classes = Attendance.objects.filter(date=today)
|
||||
total_classes = today_classes.count()
|
||||
total_students_today = AttendanceRecord.objects.filter(attendance__in=today_classes).count()
|
||||
students_present = AttendanceRecord.objects.filter(
|
||||
attendance__in=today_classes, student_attend=True
|
||||
).count()
|
||||
|
||||
# Recent Feedback
|
||||
recent_feedback = StudentFeedback.objects.order_by("-created_at")[:5]
|
||||
|
||||
# Recent Institute Feedback
|
||||
recent_institute_feedback = InstituteFeedback.objects.filter(
|
||||
is_public=True
|
||||
).order_by("-created_at")[:10]
|
||||
|
||||
# Get notices
|
||||
notices = Notice.objects.all().order_by("-created_at")
|
||||
|
||||
# Get recent activities
|
||||
recent_activities = []
|
||||
|
||||
# Add recent leaves
|
||||
for leave in recent_student_leaves:
|
||||
recent_activities.append(
|
||||
{
|
||||
"title": f"Student Leave Request",
|
||||
"description": f"{leave.student.name} requested leave for {leave.date}",
|
||||
"timestamp": leave.created_at,
|
||||
}
|
||||
# Staff Statistics
|
||||
total_staff = Staff.objects.count()
|
||||
active_staff = Staff.objects.filter(is_active=True).count()
|
||||
staff_on_leave = (
|
||||
Staff_leave.objects.filter(status=1).values("staff").distinct().count()
|
||||
)
|
||||
|
||||
for leave in recent_staff_leaves:
|
||||
recent_activities.append(
|
||||
{
|
||||
"title": f"Staff Leave Request",
|
||||
"description": f"{leave.staff.name} requested leave for {leave.date}",
|
||||
"timestamp": leave.created_at,
|
||||
}
|
||||
# Course Statistics
|
||||
total_courses = Course.objects.count()
|
||||
active_courses = (
|
||||
Course.objects.filter(student_trackings__progress_status="In Progress")
|
||||
.distinct()
|
||||
.count()
|
||||
)
|
||||
|
||||
# Add recent feedback
|
||||
for feedback in recent_feedback:
|
||||
recent_activities.append(
|
||||
{
|
||||
"title": f"New Feedback",
|
||||
"description": f"Feedback received for {feedback.teacher.name if feedback.teacher else 'Institute'}",
|
||||
"timestamp": feedback.created_at,
|
||||
}
|
||||
)
|
||||
|
||||
# Add recent institute feedback
|
||||
for feedback in recent_institute_feedback:
|
||||
recent_activities.append(
|
||||
{
|
||||
"title": f"Institute Feedback",
|
||||
"description": f"New feedback from {feedback.display_name}",
|
||||
"timestamp": feedback.created_at,
|
||||
}
|
||||
)
|
||||
|
||||
# Add recent notices
|
||||
for notice in notices:
|
||||
recent_activities.append(
|
||||
{
|
||||
"title": f"New Notice",
|
||||
"description": notice.title,
|
||||
"timestamp": notice.created_at,
|
||||
}
|
||||
)
|
||||
|
||||
# Sort all activities by timestamp
|
||||
recent_activities.sort(key=lambda x: x["timestamp"], reverse=True)
|
||||
# Take only the most recent 10 activities
|
||||
recent_activities = recent_activities[:10]
|
||||
|
||||
# Teacher Ratings
|
||||
teacher_ratings = []
|
||||
teachers = Staff.objects.filter(
|
||||
Q(designation__icontains="Teacher")
|
||||
| Q(designation__icontains="Staff")
|
||||
| Q(designation__icontains="Principal")
|
||||
| Q(designation__isnull=True)
|
||||
| Q(designation="")
|
||||
)
|
||||
|
||||
for teacher in teachers:
|
||||
feedback = StudentFeedback.objects.filter(teacher=teacher)
|
||||
avg_rating = feedback.aggregate(Avg("rating"))["rating__avg"] or 0
|
||||
total_reviews = feedback.count()
|
||||
|
||||
# Get total students taught by this teacher
|
||||
total_students = (
|
||||
AttendanceRecord.objects.filter(attendance__routine__teacher=teacher)
|
||||
.values("student")
|
||||
completed_courses = (
|
||||
Course.objects.filter(student_trackings__progress_status="Completed")
|
||||
.distinct()
|
||||
.count()
|
||||
)
|
||||
|
||||
teacher_ratings.append(
|
||||
{
|
||||
"name": teacher.name,
|
||||
"designation": teacher.designation or "Teacher",
|
||||
"image": teacher.image,
|
||||
"avg_rating": avg_rating,
|
||||
"total_reviews": total_reviews,
|
||||
"total_students": total_students,
|
||||
}
|
||||
)
|
||||
# Course Tracking Statistics
|
||||
course_trackings = CourseTracking.objects.all()
|
||||
in_progress_trackings = course_trackings.filter(progress_status="In Progress")
|
||||
completed_trackings = course_trackings.filter(progress_status="Completed")
|
||||
dropped_trackings = course_trackings.filter(progress_status="Dropped")
|
||||
|
||||
# Sort teachers by average rating (highest first)
|
||||
teacher_ratings.sort(key=lambda x: x["avg_rating"], reverse=True)
|
||||
# Recent Leave Requests
|
||||
recent_student_leaves = Student_Leave.objects.filter(
|
||||
created_at__gte=last_week
|
||||
).order_by("-created_at")[:5]
|
||||
|
||||
# Course Progress Overview
|
||||
course_progress = []
|
||||
for course in Course.objects.all():
|
||||
trackings = course.student_trackings.all()
|
||||
if trackings.exists():
|
||||
avg_progress = trackings.aggregate(
|
||||
avg_progress=Avg("completion_percentage")
|
||||
)["avg_progress"]
|
||||
course_progress.append(
|
||||
recent_staff_leaves = Staff_leave.objects.filter(
|
||||
created_at__gte=last_week
|
||||
).order_by("-created_at")[:5]
|
||||
|
||||
# Pending Leave Requests
|
||||
pending_student_leaves = Student_Leave.objects.filter(status=0)
|
||||
pending_staff_leaves = Staff_leave.objects.filter(status=0).order_by("-created_at")
|
||||
|
||||
# Attendance Statistics
|
||||
today_classes = Attendance.objects.filter(date=today)
|
||||
total_classes = today_classes.count()
|
||||
total_students_today = AttendanceRecord.objects.filter(attendance__in=today_classes).count()
|
||||
students_present = AttendanceRecord.objects.filter(
|
||||
attendance__in=today_classes, student_attend=True
|
||||
).count()
|
||||
|
||||
# Recent Feedback
|
||||
recent_feedback = StudentFeedback.objects.order_by("-created_at")[:5]
|
||||
|
||||
# Recent Institute Feedback
|
||||
recent_institute_feedback = InstituteFeedback.objects.filter(
|
||||
is_public=True
|
||||
).order_by("-created_at")[:10]
|
||||
|
||||
# Get notices
|
||||
notices = Notice.objects.all().order_by("-created_at")
|
||||
|
||||
# Get recent activities
|
||||
recent_activities = []
|
||||
|
||||
# Add recent leaves
|
||||
for leave in recent_student_leaves:
|
||||
recent_activities.append(
|
||||
{
|
||||
"course": course,
|
||||
"total_students": trackings.count(),
|
||||
"in_progress": trackings.filter(
|
||||
progress_status="In Progress"
|
||||
).count(),
|
||||
"completed": trackings.filter(progress_status="Completed").count(),
|
||||
"average_progress": round(avg_progress, 1) if avg_progress else 0,
|
||||
"title": f"Student Leave Request",
|
||||
"description": f"{leave.student.name} requested leave from {leave.start_date} to {leave.end_date}",
|
||||
"timestamp": leave.created_at,
|
||||
}
|
||||
)
|
||||
|
||||
# Monthly Statistics
|
||||
monthly_stats = {
|
||||
"new_students": Student.objects.filter(joining_date__gte=last_month).count(),
|
||||
"new_staff": Staff.objects.filter(joining_date__gte=last_month).count(),
|
||||
"attendance_rate": round(
|
||||
(
|
||||
AttendanceRecord.objects.filter(
|
||||
attendance__date__gte=last_month.date(), student_attend=True
|
||||
).count()
|
||||
/ AttendanceRecord.objects.filter(
|
||||
attendance__date__gte=last_month.date()
|
||||
).count()
|
||||
* 100
|
||||
for leave in recent_staff_leaves:
|
||||
recent_activities.append(
|
||||
{
|
||||
"title": f"Staff Leave Request",
|
||||
"description": f"{leave.staff.name} requested leave from {leave.start_date} to {leave.end_date}",
|
||||
"timestamp": leave.created_at,
|
||||
}
|
||||
)
|
||||
if AttendanceRecord.objects.filter(
|
||||
attendance__date__gte=last_month.date()
|
||||
).exists()
|
||||
else 0
|
||||
),
|
||||
"leave_requests": Student_Leave.objects.filter(
|
||||
created_at__gte=last_month
|
||||
).count()
|
||||
+ Staff_leave.objects.filter(created_at__gte=last_month).count(),
|
||||
}
|
||||
|
||||
context = {
|
||||
**custom_admin_site.each_context(
|
||||
request
|
||||
), # This adds the admin context, including the sidebar.
|
||||
# Student Statistics
|
||||
"total_students": total_students,
|
||||
"active_students": active_students,
|
||||
"completed_students": completed_students,
|
||||
"on_leave_students": on_leave_students,
|
||||
# Staff Statistics
|
||||
"total_staff": total_staff,
|
||||
"active_staff": active_staff,
|
||||
"staff_on_leave": staff_on_leave,
|
||||
# Course Statistics
|
||||
"total_courses": total_courses,
|
||||
"active_courses": active_courses,
|
||||
"completed_courses": completed_courses,
|
||||
# Course Tracking Statistics
|
||||
"in_progress_trackings": in_progress_trackings.count(),
|
||||
"completed_trackings": completed_trackings.count(),
|
||||
"dropped_trackings": dropped_trackings.count(),
|
||||
# Leave Requests
|
||||
"recent_student_leaves": recent_student_leaves,
|
||||
"recent_staff_leaves": recent_staff_leaves,
|
||||
"pending_student_leaves": pending_student_leaves,
|
||||
"pending_staff_leaves": pending_staff_leaves,
|
||||
# Attendance Statistics
|
||||
"total_classes_today": total_classes,
|
||||
"total_students_today": total_students_today,
|
||||
"students_present": students_present,
|
||||
"attendance_rate": round(
|
||||
(students_present / total_students_today * 100) if total_students_today > 0 else 0
|
||||
),
|
||||
# Feedback
|
||||
"recent_feedback": recent_feedback,
|
||||
"recent_institute_feedback": recent_institute_feedback,
|
||||
"teacher_ratings": teacher_ratings,
|
||||
# Course Progress
|
||||
"course_progress": course_progress,
|
||||
# Add recent feedback
|
||||
for feedback in recent_feedback:
|
||||
recent_activities.append(
|
||||
{
|
||||
"title": f"New Feedback",
|
||||
"description": f"Feedback received for {feedback.teacher.name if feedback.teacher else 'Institute'}",
|
||||
"timestamp": feedback.created_at,
|
||||
}
|
||||
)
|
||||
|
||||
# Add recent institute feedback
|
||||
for feedback in recent_institute_feedback:
|
||||
recent_activities.append(
|
||||
{
|
||||
"title": f"Institute Feedback",
|
||||
"description": f"New feedback from {feedback.display_name}",
|
||||
"timestamp": feedback.created_at,
|
||||
}
|
||||
)
|
||||
|
||||
# Add recent notices
|
||||
for notice in notices:
|
||||
recent_activities.append(
|
||||
{
|
||||
"title": f"New Notice",
|
||||
"description": notice.title,
|
||||
"timestamp": notice.created_at,
|
||||
}
|
||||
)
|
||||
|
||||
# Sort all activities by timestamp
|
||||
recent_activities.sort(key=lambda x: x["timestamp"], reverse=True)
|
||||
# Take only the most recent 10 activities
|
||||
recent_activities = recent_activities[:10]
|
||||
|
||||
# Teacher Ratings
|
||||
teacher_ratings = []
|
||||
teachers = Staff.objects.filter(
|
||||
Q(designation__icontains="Teacher")
|
||||
| Q(designation__icontains="Staff")
|
||||
| Q(designation__icontains="Principal")
|
||||
| Q(designation__isnull=True)
|
||||
| Q(designation="")
|
||||
)
|
||||
|
||||
for teacher in teachers:
|
||||
feedback = StudentFeedback.objects.filter(teacher=teacher)
|
||||
avg_rating = feedback.aggregate(Avg("rating"))["rating__avg"] or 0
|
||||
total_reviews = feedback.count()
|
||||
|
||||
# Get total students taught by this teacher
|
||||
total_students = (
|
||||
AttendanceRecord.objects.filter(attendance__routine__teacher=teacher)
|
||||
.values("student")
|
||||
.distinct()
|
||||
.count()
|
||||
)
|
||||
|
||||
teacher_ratings.append(
|
||||
{
|
||||
"name": teacher.name,
|
||||
"designation": teacher.designation or "Teacher",
|
||||
"image": teacher.image,
|
||||
"avg_rating": avg_rating,
|
||||
"total_reviews": total_reviews,
|
||||
"total_students": total_students,
|
||||
}
|
||||
)
|
||||
|
||||
# Sort teachers by average rating (highest first)
|
||||
teacher_ratings.sort(key=lambda x: x["avg_rating"], reverse=True)
|
||||
|
||||
# Course Progress Overview
|
||||
course_progress = []
|
||||
for course in Course.objects.all():
|
||||
trackings = course.student_trackings.all()
|
||||
if trackings.exists():
|
||||
avg_progress = trackings.aggregate(
|
||||
avg_progress=Avg("completion_percentage")
|
||||
)["avg_progress"]
|
||||
course_progress.append(
|
||||
{
|
||||
"course": course,
|
||||
"total_students": trackings.count(),
|
||||
"in_progress": trackings.filter(
|
||||
progress_status="In Progress"
|
||||
).count(),
|
||||
"completed": trackings.filter(progress_status="Completed").count(),
|
||||
"average_progress": round(avg_progress, 1) if avg_progress else 0,
|
||||
}
|
||||
)
|
||||
|
||||
# Monthly Statistics
|
||||
"monthly_stats": monthly_stats,
|
||||
"notices": notices, # Add notices to context
|
||||
"recent_activities": recent_activities, # Add recent activities to context
|
||||
}
|
||||
monthly_stats = {
|
||||
"new_students": Student.objects.filter(joining_date__gte=last_month).count(),
|
||||
"new_staff": Staff.objects.filter(joining_date__gte=last_month).count(),
|
||||
"attendance_rate": round(
|
||||
(
|
||||
AttendanceRecord.objects.filter(
|
||||
attendance__date__gte=last_month.date(), student_attend=True
|
||||
).count()
|
||||
/ AttendanceRecord.objects.filter(
|
||||
attendance__date__gte=last_month.date()
|
||||
).count()
|
||||
* 100
|
||||
)
|
||||
if AttendanceRecord.objects.filter(
|
||||
attendance__date__gte=last_month.date()
|
||||
).exists()
|
||||
else 0
|
||||
),
|
||||
"leave_requests": Student_Leave.objects.filter(
|
||||
created_at__gte=last_month
|
||||
).count()
|
||||
+ Staff_leave.objects.filter(created_at__gte=last_month).count(),
|
||||
}
|
||||
|
||||
return render(request, "dashboard.html", context)
|
||||
context = {
|
||||
**custom_admin_site.each_context(
|
||||
request
|
||||
), # This adds the admin context, including the sidebar.
|
||||
# Student Statistics
|
||||
"total_students": total_students,
|
||||
"active_students": active_students,
|
||||
"completed_students": completed_students,
|
||||
"on_leave_students": on_leave_students,
|
||||
# Staff Statistics
|
||||
"total_staff": total_staff,
|
||||
"active_staff": active_staff,
|
||||
"staff_on_leave": staff_on_leave,
|
||||
# Course Statistics
|
||||
"total_courses": total_courses,
|
||||
"active_courses": active_courses,
|
||||
"completed_courses": completed_courses,
|
||||
# Course Tracking Statistics
|
||||
"in_progress_trackings": in_progress_trackings.count(),
|
||||
"completed_trackings": completed_trackings.count(),
|
||||
"dropped_trackings": dropped_trackings.count(),
|
||||
# Leave Requests
|
||||
"recent_student_leaves": recent_student_leaves,
|
||||
"recent_staff_leaves": recent_staff_leaves,
|
||||
"pending_student_leaves": pending_student_leaves,
|
||||
"pending_staff_leaves": pending_staff_leaves,
|
||||
# Attendance Statistics
|
||||
"total_classes_today": total_classes,
|
||||
"total_students_today": total_students_today,
|
||||
"students_present": students_present,
|
||||
"attendance_rate": round(
|
||||
(students_present / total_students_today * 100) if total_students_today > 0 else 0
|
||||
),
|
||||
# Feedback
|
||||
"recent_feedback": recent_feedback,
|
||||
"recent_institute_feedback": recent_institute_feedback,
|
||||
"teacher_ratings": teacher_ratings,
|
||||
# Course Progress
|
||||
"course_progress": course_progress,
|
||||
# Monthly Statistics
|
||||
"monthly_stats": monthly_stats,
|
||||
"notices": notices, # Add notices to context
|
||||
"recent_activities": recent_activities, # Add recent activities to context
|
||||
}
|
||||
|
||||
return render(request, "dashboard.html", context)
|
||||
else:
|
||||
# If user doesn't belong to any specific group, try to determine user type
|
||||
print("User doesn't belong to any specific group")
|
||||
if hasattr(user, 'student'):
|
||||
print("User has student attribute, redirecting to student dashboard")
|
||||
return redirect("studentDashboard")
|
||||
elif hasattr(user, 'staff'):
|
||||
print("User has staff attribute, redirecting to teacher dashboard")
|
||||
return redirect("teacherDashboard")
|
||||
else:
|
||||
print("Unknown user type, showing default dashboard")
|
||||
return render(request, "dashboard.html", {"unknown_user_type": True})
|
||||
|
||||
|
||||
@login_required
|
||||
def update_profile(request):
|
||||
if request.method == "POST":
|
||||
user = request.user
|
||||
name = request.POST.get("name")
|
||||
email = request.POST.get("email")
|
||||
phone = request.POST.get("phone")
|
||||
address = request.POST.get("address")
|
||||
gender = request.POST.get("gender")
|
||||
dob = request.POST.get("dob")
|
||||
user_groups = user.groups.values_list("name", flat=True)
|
||||
|
||||
# Validate data
|
||||
if not all([name, email, phone]):
|
||||
messages.error(request, "Name, email and phone are required fields.")
|
||||
return redirect("studentDashboard")
|
||||
|
||||
# Update profile based on user type
|
||||
try:
|
||||
if hasattr(user, "student"):
|
||||
student = user
|
||||
student.name = name
|
||||
student.email = email
|
||||
student.phone = phone
|
||||
student.address = address
|
||||
student.gender = gender
|
||||
if dob:
|
||||
student.dob = dob
|
||||
|
||||
# Handle profile image
|
||||
if "profile_image" in request.FILES:
|
||||
image = request.FILES["profile_image"]
|
||||
# Handle profile image update
|
||||
if "profile_image" in request.FILES:
|
||||
try:
|
||||
image = request.FILES["profile_image"]
|
||||
|
||||
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 updated successfully.")
|
||||
|
||||
elif hasattr(user, "staff"):
|
||||
staff = user
|
||||
staff.name = name
|
||||
staff.email = email
|
||||
staff.phone = phone
|
||||
staff.address = address
|
||||
staff.gender = gender
|
||||
if dob:
|
||||
staff.dob = dob
|
||||
|
||||
# Handle profile image
|
||||
if "profile_image" in request.FILES:
|
||||
image = request.FILES["profile_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 updated successfully.")
|
||||
|
||||
else:
|
||||
messages.error(request, "User profile not found.")
|
||||
|
||||
except Exception as e:
|
||||
messages.error(request, f"Error updating profile: {str(e)}")
|
||||
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 or staff member.")
|
||||
|
||||
except (Student.DoesNotExist, Staff.DoesNotExist) as e:
|
||||
messages.error(request, "User profile not found in the database.")
|
||||
except Exception as e:
|
||||
messages.error(request, f"Error updating profile picture: {str(e)}")
|
||||
else:
|
||||
messages.error(request, "No profile picture uploaded.")
|
||||
|
||||
# Redirect based on user type
|
||||
if hasattr(user, "student"):
|
||||
if "Student" in user_groups:
|
||||
return redirect("studentDashboard")
|
||||
elif hasattr(user, "staff"):
|
||||
elif "Teacher" in user_groups:
|
||||
return redirect("teacherDashboard")
|
||||
else:
|
||||
return redirect("dashboard")
|
||||
@@ -458,17 +438,26 @@ def change_password(request):
|
||||
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'
|
||||
|
||||
# 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("studentDashboard")
|
||||
|
||||
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("studentDashboard")
|
||||
|
||||
# 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("studentDashboard")
|
||||
|
||||
@@ -476,11 +465,16 @@ def change_password(request):
|
||||
try:
|
||||
user.set_password(new_password)
|
||||
user.save()
|
||||
if is_ajax:
|
||||
return JsonResponse({"success": True})
|
||||
|
||||
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)}")
|
||||
|
||||
# Redirect based on user type
|
||||
@@ -657,4 +651,215 @@ def delete_notice(request, notice_id):
|
||||
return JsonResponse({"success": False, "error": "Invalid request method"})
|
||||
|
||||
|
||||
@login_required
|
||||
def student_dashboard(request):
|
||||
student = request.user.student
|
||||
today = timezone.now().date()
|
||||
|
||||
# Get attendance summary
|
||||
attendance_records = AttendanceRecord.objects.filter(student=student)
|
||||
total_classes = attendance_records.count()
|
||||
attended_classes = attendance_records.filter(student_attend=True).count()
|
||||
attendance_percentage = (attended_classes / total_classes * 100) if total_classes > 0 else 0
|
||||
|
||||
# Calculate current streak
|
||||
current_streak = 0
|
||||
longest_streak = 0
|
||||
temp_streak = 1
|
||||
|
||||
for record in attendance_records.order_by('-attendance__date'):
|
||||
if record.student_attend:
|
||||
current_streak += 1
|
||||
temp_streak += 1
|
||||
longest_streak = max(longest_streak, temp_streak)
|
||||
else:
|
||||
break
|
||||
|
||||
attendance_summary = {
|
||||
'total_classes': total_classes,
|
||||
'attendance_percentage': attendance_percentage,
|
||||
'current_streak': current_streak,
|
||||
'longest_streak': longest_streak
|
||||
}
|
||||
|
||||
# Get course tracking summary
|
||||
course_trackings = CourseTracking.objects.filter(student=student)
|
||||
course_summary = {
|
||||
'total_courses': course_trackings.count(),
|
||||
'completed_courses': course_trackings.filter(progress_status='Completed').count(),
|
||||
'ongoing_courses': course_trackings.filter(progress_status='In Progress').count(),
|
||||
'completion_percentage': (
|
||||
sum(tracking.completion_percentage for tracking in course_trackings) / course_trackings.count()
|
||||
if course_trackings.exists() else 0
|
||||
)
|
||||
}
|
||||
|
||||
# Get recent leaves
|
||||
recent_leaves = Student_Leave.objects.filter(student=student).order_by('-created_at')[:5]
|
||||
|
||||
# Get recent feedback
|
||||
recent_feedback = StudentFeedback.objects.filter(student=student).order_by('-created_at')[:5]
|
||||
|
||||
# Get notices
|
||||
notices = Notice.objects.all().order_by('-created_at')[:5]
|
||||
|
||||
# Get attendance records
|
||||
attendance_records = AttendanceRecord.objects.filter(student=student).order_by('-attendance__date')[:5]
|
||||
|
||||
# Get leave counts
|
||||
pending_leaves = Student_Leave.objects.filter(student=student, status=0).count()
|
||||
approved_leaves = Student_Leave.objects.filter(student=student, status=1).count()
|
||||
rejected_leaves = Student_Leave.objects.filter(student=student, status=2).count()
|
||||
|
||||
# Get course details from course tracking
|
||||
course_details = []
|
||||
for tracking in course_trackings:
|
||||
course_info = {
|
||||
'name': tracking.course.name,
|
||||
'start_date': tracking.start_date,
|
||||
'duration': tracking.course.duration,
|
||||
'duration_type': tracking.course.duration_type,
|
||||
'current_semester': tracking.current_semester,
|
||||
'progress_status': tracking.progress_status,
|
||||
'completion_percentage': tracking.completion_percentage,
|
||||
'semester_start_date': tracking.semester_start_date,
|
||||
'semester_end_date': tracking.semester_end_date,
|
||||
'expected_end_date': tracking.expected_end_date,
|
||||
'actual_end_date': tracking.actual_end_date,
|
||||
'remaining_days': tracking.remaining_days,
|
||||
'total_remaining_days': tracking.total_remaining_days
|
||||
}
|
||||
course_details.append(course_info)
|
||||
|
||||
context = {
|
||||
'student': student,
|
||||
'attendance_summary': attendance_summary,
|
||||
'course_summary': course_summary,
|
||||
'recent_leaves': recent_leaves,
|
||||
'recent_feedback': recent_feedback,
|
||||
'notices': notices,
|
||||
'attendance_records': attendance_records,
|
||||
'pending_leaves': pending_leaves,
|
||||
'approved_leaves': approved_leaves,
|
||||
'rejected_leaves': rejected_leaves,
|
||||
'course_details': course_details,
|
||||
}
|
||||
return render(request, 'student_dashboard.html', context)
|
||||
|
||||
@login_required
|
||||
def teacher_dashboard(request):
|
||||
teacher = request.user.teacher
|
||||
today = timezone.now().date()
|
||||
|
||||
# Get today's routines
|
||||
today_routines = Routine.objects.filter(
|
||||
teacher=teacher,
|
||||
day_of_week=today.weekday()
|
||||
).order_by('start_time')
|
||||
|
||||
# Get attendance summary
|
||||
attendance_records = Attendance.objects.filter(routine__teacher=teacher)
|
||||
total_classes = attendance_records.count()
|
||||
total_students = AttendanceRecord.objects.filter(attendance__routine__teacher=teacher).count()
|
||||
present_students = AttendanceRecord.objects.filter(
|
||||
attendance__routine__teacher=teacher,
|
||||
student_attend=True
|
||||
).count()
|
||||
|
||||
attendance_summary = {
|
||||
'total_classes': total_classes,
|
||||
'total_students': total_students,
|
||||
'present_students': present_students,
|
||||
'attendance_percentage': (present_students / total_students * 100) if total_students > 0 else 0
|
||||
}
|
||||
|
||||
# Get recent leaves
|
||||
recent_leaves = Student_Leave.objects.filter(
|
||||
Q(status=0) | Q(status=1)
|
||||
).order_by('-created_at')[:5]
|
||||
|
||||
# Get recent feedback
|
||||
recent_feedback = StudentFeedback.objects.filter(teacher=teacher).order_by('-created_at')[:5]
|
||||
|
||||
# Get notices
|
||||
notices = Notice.objects.all().order_by('-created_at')[:5]
|
||||
|
||||
# Get attendance records
|
||||
attendance_records = Attendance.objects.filter(routine__teacher=teacher).order_by('-date')[:5]
|
||||
|
||||
# Get leave counts
|
||||
pending_leaves = Student_Leave.objects.filter(status=0).count()
|
||||
approved_leaves = Student_Leave.objects.filter(status=1).count()
|
||||
rejected_leaves = Student_Leave.objects.filter(status=2).count()
|
||||
|
||||
context = {
|
||||
'teacher': teacher,
|
||||
'today_routines': today_routines,
|
||||
'attendance_summary': attendance_summary,
|
||||
'recent_leaves': recent_leaves,
|
||||
'recent_feedback': recent_feedback,
|
||||
'notices': notices,
|
||||
'attendance_records': attendance_records,
|
||||
'pending_leaves': pending_leaves,
|
||||
'approved_leaves': approved_leaves,
|
||||
'rejected_leaves': rejected_leaves,
|
||||
}
|
||||
return render(request, 'teacher_dashboard.html', context)
|
||||
|
||||
@login_required
|
||||
@require_POST
|
||||
def save_fcm_token(request):
|
||||
try:
|
||||
data = json.loads(request.body)
|
||||
token = data.get('token')
|
||||
|
||||
if not token:
|
||||
return JsonResponse({'error': 'Token is required'}, status=400)
|
||||
|
||||
user = request.user
|
||||
user_groups = user.groups.values_list("name", flat=True)
|
||||
|
||||
# Save token to the appropriate user model
|
||||
if "Student" in user_groups:
|
||||
user.fcm_token = token
|
||||
user.save()
|
||||
elif "Teacher" in user_groups:
|
||||
user.fcm_token = token
|
||||
user.save()
|
||||
|
||||
# Update or create FCMDevice
|
||||
device, created = FCMDevice.objects.update_or_create(
|
||||
token=token,
|
||||
defaults={'is_active': True}
|
||||
)
|
||||
|
||||
return JsonResponse({
|
||||
'status': 'success',
|
||||
'device_id': device.id,
|
||||
'created': created
|
||||
})
|
||||
except json.JSONDecodeError:
|
||||
return JsonResponse({'error': 'Invalid JSON'}, status=400)
|
||||
except Exception as e:
|
||||
return JsonResponse({'error': str(e)}, status=500)
|
||||
|
||||
def serve_firebase_sw(request):
|
||||
"""Serve Firebase service worker with correct MIME type"""
|
||||
|
||||
# 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')
|
||||
|
||||
response = serve(request, 'firebase-messaging-sw.js', os.path.dirname(sw_path))
|
||||
response['Content-Type'] = 'application/javascript'
|
||||
return response
|
||||
|
||||
@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})
|
||||
Reference in new issue
Block a user