Files
Student-Management-System-I…/app/views.py
T

661 lines
22 KiB
Python

from app.models import FCMDevice
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 .models import (
Student,
Course,
CourseTracking,
Student_Leave,
Staff_leave,
Attendance,
AttendanceRecord,
StudentFeedback,
Routine,
Staff,
Notice,
Institute,
InstituteFeedback,
Subject,
Batch,
)
from app.admin import custom_admin_site
from django.views.decorators.http import require_http_methods, require_GET
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 django.conf import settings
from dotenv import load_dotenv
# Import views from studentviews.py
from .studentviews import (
studentDashboard,
request_leave,
submit_feedback,
submit_institute_feedback,
get_subject_files,
)
# Import views from staffviews.py
from .staffviews import (
teacherDashboard,
request_staff_leave,
submit_staff_institute_feedback,
save_attendance,
get_subject_schedule,
teacher_update_profile_picture,
teacher_change_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:
return redirect("studentDashboard")
elif "Teacher" in user_groups:
return redirect("teacherDashboard")
# 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,
}
)
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,
}
)
# 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 = {
"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(),
}
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)
@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")
# 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"]
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"]
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)}")
# Redirect based on user type
if hasattr(user, "student"):
return redirect("studentDashboard")
elif hasattr(user, "staff"):
return redirect("teacherDashboard")
else:
return redirect("dashboard")
return redirect("dashboard")
@login_required
def change_password(request):
if request.method == "POST":
user = request.user
current_password = request.POST.get("current_password")
new_password = request.POST.get("new_password")
confirm_password = request.POST.get("confirm_password")
# Validate input
if not all([current_password, new_password, confirm_password]):
messages.error(request, "All password fields are required.")
return redirect("studentDashboard")
if new_password != confirm_password:
messages.error(request, "New passwords do not match.")
return redirect("studentDashboard")
# Check current password
if not user.check_password(current_password):
messages.error(request, "Current password is incorrect.")
return redirect("studentDashboard")
# Set new password
try:
user.set_password(new_password)
user.save()
messages.success(
request, "Password changed successfully. Please login again."
)
return redirect("login")
except Exception as e:
messages.error(request, f"Error changing password: {str(e)}")
# Redirect based on user type
if hasattr(user, "student"):
return redirect("studentDashboard")
elif hasattr(user, "staff"):
return redirect("teacherDashboard")
else:
return redirect("dashboard")
return redirect("dashboard")
@login_required
@require_GET
def get_subjects(request):
"""Get subjects for a course and semester"""
course_id = request.GET.get("course_id")
semester = request.GET.get("semester", 1)
if not course_id:
return JsonResponse({"success": False, "message": "Course ID is required"})
try:
subjects = Subject.objects.filter(
course_id=course_id, semester_or_year=semester
).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__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(Student_Leave, 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(Student_Leave, 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(Staff_leave, 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(Staff_leave, 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":
title = request.POST.get("title")
message = request.POST.get("message")
image = request.FILES.get("image")
if title and message:
notice = Notice.objects.create(title=title, message=message, image=image)
messages.success(request, "Notice added successfully.")
else:
messages.error(request, "Title and message are required.")
return redirect("dashboard")
@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"})