815 lines
29 KiB
Python
815 lines
29 KiB
Python
from django.contrib import admin
|
|
from .models import (
|
|
Institute,
|
|
Course,
|
|
Subject,
|
|
SubjectFile,
|
|
Student,
|
|
Staff,
|
|
Batch,
|
|
Attendance,
|
|
AttendanceRecord,
|
|
Notice,
|
|
Routine,
|
|
Staff_leave,
|
|
Student_Leave,
|
|
StudentFeedback,
|
|
CourseTracking,
|
|
InstituteFeedback,
|
|
StaffInstituteFeedback,
|
|
TOTPSecret,
|
|
ResetToken,
|
|
)
|
|
from .firebase import FCMDevice
|
|
from django.forms import ModelForm
|
|
from django.contrib.auth.models import User, Group
|
|
from django.contrib.auth.admin import UserAdmin, GroupAdmin
|
|
from app.forms import StaffAdminForm, StudentAdminForm
|
|
from django.urls import path
|
|
from django.http import JsonResponse
|
|
import json
|
|
from django.db import transaction
|
|
from django.db.models import Q
|
|
from datetime import datetime
|
|
|
|
# Register your models here.
|
|
|
|
|
|
class CustomAdminSite(admin.AdminSite):
|
|
def get_app_list(self, request):
|
|
# Original app list
|
|
app_list = super().get_app_list(request)
|
|
|
|
model_map = {
|
|
# Authentication Models
|
|
"User": {
|
|
"group": "Authentication",
|
|
"group_label": "authentication",
|
|
},
|
|
"Group": {
|
|
"group": "Authentication",
|
|
"group_label": "authentication",
|
|
},
|
|
"TOTPSecret": {
|
|
"group": "Authentication",
|
|
"group_label": "authentication",
|
|
},
|
|
"ResetToken": {
|
|
"group": "Authentication",
|
|
"group_label": "authentication",
|
|
},
|
|
# Organization Models
|
|
"Institute": {
|
|
"group": "Organization",
|
|
"group_label": "organization",
|
|
},
|
|
"Batch": {
|
|
"group": "Organization",
|
|
"group_label": "organization",
|
|
},
|
|
"Notice": {
|
|
"group": "Organization",
|
|
"group_label": "organization",
|
|
},
|
|
# Course Management Models
|
|
"Course": {
|
|
"group": "Course Management",
|
|
"group_label": "course_management",
|
|
},
|
|
"Subject": {
|
|
"group": "Course Management",
|
|
"group_label": "course_management",
|
|
},
|
|
"SubjectFile": {
|
|
"group": "Course Management",
|
|
"group_label": "course_management",
|
|
},
|
|
"CourseTracking": {
|
|
"group": "Course Management",
|
|
"group_label": "course_management",
|
|
},
|
|
# Human Management Models
|
|
"Student": {
|
|
"group": "Human Management",
|
|
"group_label": "human_management",
|
|
},
|
|
"Staff": {
|
|
"group": "Human Management",
|
|
"group_label": "human_management",
|
|
},
|
|
"Routine": {
|
|
"group": "Human Management",
|
|
"group_label": "human_management",
|
|
},
|
|
"Staff_leave": {
|
|
"group": "Human Management",
|
|
"group_label": "human_management",
|
|
},
|
|
"Student_Leave": {
|
|
"group": "Human Management",
|
|
"group_label": "human_management",
|
|
},
|
|
# Attendance Models
|
|
"Attendance": {
|
|
"group": "Attendance",
|
|
"group_label": "attendance",
|
|
},
|
|
"AttendanceRecord": {
|
|
"group": "Attendance",
|
|
"group_label": "attendance",
|
|
},
|
|
# Feedback Models
|
|
"StudentFeedback": {
|
|
"group": "Feedback",
|
|
"group_label": "feedback",
|
|
},
|
|
"InstituteFeedback": {
|
|
"group": "Feedback",
|
|
"group_label": "feedback",
|
|
},
|
|
"StaffInstituteFeedback": {
|
|
"group": "Feedback",
|
|
"group_label": "feedback",
|
|
},
|
|
# Device Management
|
|
"FCMDevice": {
|
|
"group": "Device Management",
|
|
"group_label": "device_management",
|
|
},
|
|
}
|
|
|
|
grouped_app_list = [{"name": "Main", "app_label": "dashboard", "models": []}]
|
|
grouped_models = {}
|
|
|
|
for app in app_list:
|
|
for model in app["models"]:
|
|
model_name = model["object_name"]
|
|
if model_name in model_map:
|
|
group = model_map[model_name]["group"]
|
|
if group not in grouped_models:
|
|
grouped_models[group] = {
|
|
"name": group,
|
|
"app_label": model_map[model_name]["group_label"],
|
|
"models": [],
|
|
}
|
|
grouped_models[group]["models"].append(model)
|
|
|
|
dashboard_item = {
|
|
"name": "Dashboard",
|
|
"app_label": "dashboard",
|
|
"models": [
|
|
{
|
|
"name": "Dashboard",
|
|
"object_name": "Dashboard",
|
|
"perms": {"has_module_perms": True},
|
|
"admin_url": "/app/dashboard",
|
|
"view_only": True,
|
|
}
|
|
],
|
|
}
|
|
|
|
grouped_app_list = [dashboard_item] + list(grouped_models.values())
|
|
|
|
return grouped_app_list
|
|
|
|
|
|
# Create a custom admin site instance
|
|
custom_admin_site = CustomAdminSite(name="custom_admin")
|
|
|
|
|
|
@admin.register(Institute, site=custom_admin_site)
|
|
class InstituteModel(admin.ModelAdmin):
|
|
list_display = ("id", "name", "address", "phone")
|
|
search_fields = ("name", "phone")
|
|
list_filter = ("name", "phone")
|
|
advanced_filter_fields = ("name", "phone")
|
|
|
|
|
|
@admin.register(Course, site=custom_admin_site)
|
|
class CourseModel(admin.ModelAdmin):
|
|
list_display = ("id", "name", "duration", "duration_type", "get_total_duration")
|
|
search_fields = ("name", "duration", "duration_type")
|
|
list_filter = ("duration_type", "duration")
|
|
advanced_filter_fields = ("name", "duration", "duration_type")
|
|
|
|
def get_total_duration(self, obj):
|
|
if obj.duration_type == "Semester":
|
|
return f"{obj.duration} years ({obj.duration * 2} semesters)"
|
|
return f"{obj.duration} year{'s' if obj.duration > 1 else ''}"
|
|
|
|
get_total_duration.short_description = "Total Duration"
|
|
|
|
fieldsets = (
|
|
(None, {"fields": ("name",)}),
|
|
(
|
|
"Duration Settings",
|
|
{
|
|
"fields": ("duration", "duration_type"),
|
|
"description": "For yearly courses, duration is in years. For semester-based courses, duration is in years (2 semesters per year).",
|
|
},
|
|
),
|
|
)
|
|
|
|
|
|
@admin.register(Batch, site=custom_admin_site)
|
|
class BatchAdmin(admin.ModelAdmin):
|
|
list_display = ("name", "start_date", "end_date")
|
|
search_fields = ("name", "start_date", "end_date")
|
|
list_filter = ("name", "start_date", "end_date")
|
|
advanced_filter_fields = ("name", "start_date", "end_date")
|
|
|
|
|
|
@admin.register(Subject, site=custom_admin_site)
|
|
class SubjectModel(admin.ModelAdmin):
|
|
list_display = ("id", "name", "course", "get_period_display", "has_syllabus", "file_count")
|
|
search_fields = ("name", "course__name")
|
|
list_filter = ("course", "semester_or_year")
|
|
advanced_filter_fields = ("name", "course", "semester_or_year")
|
|
|
|
def has_syllabus(self, obj):
|
|
return bool(obj.syllabus_pdf)
|
|
|
|
has_syllabus.boolean = True
|
|
has_syllabus.short_description = "Has Syllabus"
|
|
|
|
def file_count(self, obj):
|
|
return obj.subjectfile_set.count()
|
|
|
|
file_count.short_description = "Additional Files"
|
|
|
|
def get_period_display(self, obj):
|
|
if obj.course.duration_type == "Semester":
|
|
return f"Semester {obj.semester_or_year}"
|
|
return f"Year {obj.semester_or_year}"
|
|
|
|
get_period_display.short_description = "Period"
|
|
|
|
def add_view(self, request, form_url="", extra_context=None):
|
|
extra_context = extra_context or {}
|
|
extra_context["show_save_and_add_another"] = True
|
|
extra_context["show_save"] = False
|
|
return super().add_view(request, form_url, extra_context)
|
|
|
|
def response_add(self, request, obj, post_url_continue=None):
|
|
if "_addanother" in request.POST:
|
|
# Pre-fill the course and semester fields for the next entry
|
|
return self.response_post_save_add(request, obj)
|
|
return super().response_add(request, obj, post_url_continue)
|
|
|
|
def get_form(self, request, obj=None, **kwargs):
|
|
form = super().get_form(request, obj, **kwargs)
|
|
if obj and obj.course:
|
|
if obj.course.duration_type == "Semester":
|
|
form.base_fields["semester_or_year"].label = "Semester"
|
|
form.base_fields[
|
|
"semester_or_year"
|
|
].help_text = f"Enter semester number (1-{obj.course.duration * 2})"
|
|
else:
|
|
form.base_fields["semester_or_year"].label = "Year"
|
|
form.base_fields[
|
|
"semester_or_year"
|
|
].help_text = f"Enter year number (1-{obj.course.duration})"
|
|
|
|
# Keep the last used course selected for next entry
|
|
if not obj and request.method == "GET":
|
|
if "course" in request.GET:
|
|
form.base_fields["course"].initial = request.GET["course"]
|
|
if "semester_or_year" in request.GET:
|
|
form.base_fields["semester_or_year"].initial = request.GET[
|
|
"semester_or_year"
|
|
]
|
|
return form
|
|
|
|
def response_post_save_add(self, request, obj):
|
|
from django.http import HttpResponseRedirect
|
|
from django.urls import reverse
|
|
|
|
opts = self.model._meta
|
|
url = reverse(f"admin:{opts.app_label}_{opts.model_name}_add")
|
|
return HttpResponseRedirect(
|
|
f"{url}?course={obj.course.id}&semester_or_year={obj.semester_or_year}"
|
|
)
|
|
|
|
|
|
@admin.register(Student, site=custom_admin_site)
|
|
class StudentAdmin(admin.ModelAdmin):
|
|
form = StudentAdminForm
|
|
list_display = ("id", "name", "phone", "course", "status")
|
|
search_fields = ("name", "phone", "course__name")
|
|
list_filter = ("course", "status", "gender", "joining_date")
|
|
advanced_filter_fields = ("name", "phone", "course", "batch", "status")
|
|
|
|
def has_view_permission(self, request, obj=None):
|
|
"""Check if user has view permission"""
|
|
return request.user.has_perm("app.view_student")
|
|
|
|
def has_add_permission(self, request):
|
|
"""Check if user has add permission"""
|
|
return request.user.has_perm("app.add_student")
|
|
|
|
def has_change_permission(self, request, obj=None):
|
|
"""Check if user has change permission"""
|
|
return request.user.has_perm("app.change_student")
|
|
|
|
def has_delete_permission(self, request, obj=None):
|
|
"""Check if user has delete permission"""
|
|
return request.user.has_perm("app.delete_student")
|
|
|
|
def has_module_permission(self, request):
|
|
"""Check if user has any permissions for this app"""
|
|
return request.user.has_module_perms("app")
|
|
|
|
def get_readonly_fields(self, request, obj=None):
|
|
if obj:
|
|
return self.readonly_fields + ("password",)
|
|
return self.readonly_fields
|
|
|
|
|
|
@admin.register(Staff, site=custom_admin_site)
|
|
class StaffAdmin(admin.ModelAdmin):
|
|
form = StaffAdminForm
|
|
list_display = ("id", "name", "phone", "designation", "joining_date")
|
|
search_fields = ("name", "phone", "designation")
|
|
list_filter = ("designation", "joining_date", "gender")
|
|
advanced_filter_fields = ("name", "phone", "designation")
|
|
readonly_fields = ("password",)
|
|
ordering = ("name",)
|
|
filter_horizontal = ("groups",)
|
|
|
|
def has_view_permission(self, request, obj=None):
|
|
"""Check if user has view permission"""
|
|
return request.user.has_perm("app.view_staff")
|
|
|
|
def has_add_permission(self, request):
|
|
"""Check if user has add permission"""
|
|
return request.user.has_perm("app.add_staff")
|
|
|
|
def has_change_permission(self, request, obj=None):
|
|
"""Check if user has change permission"""
|
|
return request.user.has_perm("app.change_staff")
|
|
|
|
def has_delete_permission(self, request, obj=None):
|
|
"""Check if user has delete permission"""
|
|
return request.user.has_perm("app.delete_staff")
|
|
|
|
def has_module_permission(self, request):
|
|
"""Check if user has any permissions for this app"""
|
|
return request.user.has_module_perms("app")
|
|
|
|
def get_readonly_fields(self, request, obj=None):
|
|
if obj:
|
|
return self.readonly_fields + ("password",)
|
|
return self.readonly_fields
|
|
|
|
|
|
class AttendanceRecordForm(ModelForm):
|
|
def clean(self):
|
|
cleaned_data = super().clean()
|
|
if not cleaned_data.get("student"):
|
|
if self.instance and self.instance.pk:
|
|
cleaned_data["student"] = self.instance.student
|
|
return cleaned_data
|
|
|
|
class Meta:
|
|
model = AttendanceRecord
|
|
fields = "__all__"
|
|
|
|
|
|
class AttendanceRecordInline(admin.TabularInline):
|
|
model = AttendanceRecord
|
|
form = AttendanceRecordForm
|
|
extra = 0
|
|
can_delete = False # Prevent deletion
|
|
|
|
def get_formset(self, request, obj=None, **kwargs):
|
|
formset = super().get_formset(request, obj, **kwargs)
|
|
return formset
|
|
|
|
|
|
@admin.register(Attendance, site=custom_admin_site)
|
|
class AttendanceAdmin(admin.ModelAdmin):
|
|
list_display = ["date", "routine", "class_status", "teacher", "teacher_attend"]
|
|
inlines = [AttendanceRecordInline]
|
|
search_fields = ("date", "routine__name", "teacher__name")
|
|
list_filter = ("date", "routine", "teacher")
|
|
advanced_filter_fields = ("date", "routine", "teacher")
|
|
|
|
def save_model(self, request, obj, form, change):
|
|
is_new = not obj.pk
|
|
super().save_model(request, obj, form, change)
|
|
|
|
if is_new and obj.routine:
|
|
students = Student.objects.filter(routines__routine=obj.routine).distinct()
|
|
|
|
for student in students:
|
|
AttendanceRecord.objects.create(
|
|
attendance=obj, student=student, student_attend=False
|
|
)
|
|
|
|
def save_formset(self, request, form, formset, change):
|
|
instances = formset.save(commit=False)
|
|
|
|
# Preserve existing records
|
|
for instance in instances:
|
|
if instance.pk and not instance.student_id:
|
|
original = AttendanceRecord.objects.get(pk=instance.pk)
|
|
instance.student = original.student
|
|
instance.save()
|
|
|
|
formset.save_m2m()
|
|
|
|
|
|
@admin.register(Notice, site=custom_admin_site)
|
|
class NoticeAdmin(admin.ModelAdmin):
|
|
list_display = ("title", "message", "created_at")
|
|
search_fields = ("title", "message")
|
|
list_filter = ("title", "message")
|
|
advanced_filter_fields = ("title", "message")
|
|
|
|
|
|
@admin.register(Routine, site=custom_admin_site)
|
|
class RoutineAdmin(admin.ModelAdmin):
|
|
list_display = [
|
|
"course",
|
|
"subject",
|
|
"teacher",
|
|
"start_time",
|
|
"end_time",
|
|
"semester_or_year",
|
|
"is_active",
|
|
]
|
|
list_filter = ["is_active", "course", "subject", "teacher", "semester_or_year"]
|
|
search_fields = ["course__name", "subject__name", "teacher__name"]
|
|
ordering = ["start_time"]
|
|
change_form_template = "admin/app/routine/change_form.html"
|
|
|
|
def get_urls(self):
|
|
urls = super().get_urls()
|
|
custom_urls = [
|
|
path(
|
|
"add-multiple/",
|
|
self.admin_site.admin_view(self.save_routines),
|
|
name="routine-add-multiple",
|
|
),
|
|
]
|
|
return custom_urls + urls
|
|
|
|
def save_routines(self, request):
|
|
if request.method == "POST":
|
|
try:
|
|
data = json.loads(request.body)
|
|
routines = data.get("routines", [])
|
|
|
|
if not routines:
|
|
return JsonResponse(
|
|
{"success": False, "message": "No routines data provided"}
|
|
)
|
|
|
|
with (
|
|
transaction.atomic()
|
|
): # Use transaction to ensure all routines are created or none
|
|
created_routines = []
|
|
for index, routine_data in enumerate(routines):
|
|
try:
|
|
# Validate required fields
|
|
required_fields = [
|
|
"course",
|
|
"subject",
|
|
"teacher",
|
|
"start_time",
|
|
"end_time",
|
|
"semester_or_year",
|
|
]
|
|
missing_fields = [
|
|
field
|
|
for field in required_fields
|
|
if field not in routine_data
|
|
or not routine_data.get(field)
|
|
]
|
|
|
|
if missing_fields:
|
|
error_msg = f"Missing required fields: {', '.join(missing_fields)}"
|
|
raise ValueError(error_msg)
|
|
|
|
# Convert IDs to integers
|
|
try:
|
|
course_id = int(routine_data["course"])
|
|
subject_id = int(routine_data["subject"])
|
|
teacher_id = int(routine_data["teacher"])
|
|
semester = int(routine_data["semester_or_year"])
|
|
|
|
except (ValueError, TypeError) as e:
|
|
raise ValueError(f"Error parsing IDs: {str(e)}")
|
|
|
|
# Validate time format
|
|
try:
|
|
start_time = datetime.strptime(
|
|
routine_data["start_time"], "%H:%M"
|
|
).time()
|
|
end_time = datetime.strptime(
|
|
routine_data["end_time"], "%H:%M"
|
|
).time()
|
|
except ValueError as e:
|
|
raise ValueError(
|
|
"Invalid time format. Please use HH:MM format."
|
|
)
|
|
|
|
# Check for existing routine
|
|
existing_routine = Routine.objects.filter(
|
|
course_id=course_id,
|
|
subject_id=subject_id,
|
|
semester_or_year=semester,
|
|
start_time=start_time,
|
|
end_time=end_time,
|
|
).first()
|
|
|
|
if existing_routine:
|
|
# Update existing routine
|
|
existing_routine.teacher_id = teacher_id
|
|
existing_routine.save()
|
|
created_routines.append(existing_routine)
|
|
else:
|
|
# Create new routine
|
|
routine = Routine.objects.create(
|
|
course_id=course_id,
|
|
subject_id=subject_id,
|
|
teacher_id=teacher_id,
|
|
start_time=start_time,
|
|
end_time=end_time,
|
|
semester_or_year=semester,
|
|
is_active=True,
|
|
)
|
|
created_routines.append(routine)
|
|
|
|
except ValueError as e:
|
|
raise # Re-raise to trigger rollback
|
|
except Exception as e:
|
|
raise # Re-raise to trigger rollback
|
|
|
|
return JsonResponse(
|
|
{
|
|
"success": True,
|
|
"message": f"Successfully saved {len(created_routines)} routines",
|
|
"routines": [
|
|
{
|
|
"id": r.id,
|
|
"course": r.course.name,
|
|
"subject": r.subject.name,
|
|
"teacher": r.teacher.name,
|
|
"start_time": r.start_time.strftime("%H:%M"),
|
|
"end_time": r.end_time.strftime("%H:%M"),
|
|
"semester_or_year": r.semester_or_year,
|
|
}
|
|
for r in created_routines
|
|
],
|
|
}
|
|
)
|
|
|
|
except ValueError as e:
|
|
return JsonResponse({"success": False, "message": str(e)})
|
|
except json.JSONDecodeError as e:
|
|
return JsonResponse(
|
|
{"success": False, "message": f"Invalid JSON data: {str(e)}"}
|
|
)
|
|
except Exception as e:
|
|
return JsonResponse({"success": False, "message": str(e)})
|
|
|
|
return JsonResponse({"success": False, "message": "Invalid request method"})
|
|
|
|
def formfield_for_foreignkey(self, db_field, request, **kwargs):
|
|
if db_field.name == "subject":
|
|
if request.GET.get("course"):
|
|
kwargs["queryset"] = Subject.objects.filter(
|
|
course_id=request.GET.get("course"),
|
|
semester_or_year=request.GET.get("semester_or_year", 1),
|
|
)
|
|
else:
|
|
kwargs["queryset"] = Subject.objects.none()
|
|
elif db_field.name == "teacher":
|
|
kwargs["queryset"] = Staff.objects.filter(
|
|
Q(designation__icontains="Teacher")
|
|
| Q(designation__icontains="Staff")
|
|
| Q(designation__icontains="Principal")
|
|
| Q(designation__isnull=True)
|
|
| Q(designation="")
|
|
).order_by("name")
|
|
return super().formfield_for_foreignkey(db_field, request, **kwargs)
|
|
|
|
def get_form(self, request, obj=None, **kwargs):
|
|
form = super().get_form(request, obj, **kwargs)
|
|
if not obj: # Only for adding new routines
|
|
form.base_fields["course"].widget.attrs["class"] = "select2"
|
|
form.base_fields["subject"].widget.attrs["class"] = "select2"
|
|
form.base_fields["teacher"].widget.attrs["class"] = "select2"
|
|
form.base_fields["semester_or_year"].initial = 1
|
|
return form
|
|
|
|
def add_view(self, request, form_url="", extra_context=None):
|
|
extra_context = extra_context or {}
|
|
extra_context["show_save_and_add_another"] = True
|
|
return super().add_view(request, form_url, extra_context)
|
|
|
|
class Media:
|
|
css = {
|
|
"all": (
|
|
"https://cdn.jsdelivr.net/npm/select2@4.1.0-rc.0/dist/css/select2.min.css",
|
|
)
|
|
}
|
|
js = ("https://cdn.jsdelivr.net/npm/select2@4.1.0-rc.0/dist/js/select2.min.js",)
|
|
|
|
|
|
@admin.register(Staff_leave, site=custom_admin_site)
|
|
class StaffLeaveAdmin(admin.ModelAdmin):
|
|
list_display = ("staff", "start_date", "end_date", "get_status_display", "created_at")
|
|
list_filter = ("status", "start_date", "end_date", "created_at")
|
|
search_fields = ("staff__name", "message")
|
|
readonly_fields = ("created_at", "updated_at")
|
|
ordering = ("-created_at",)
|
|
raw_id_fields = ("staff",)
|
|
|
|
|
|
@admin.register(Student_Leave, site=custom_admin_site)
|
|
class StudentLeaveAdmin(admin.ModelAdmin):
|
|
list_display = ("student", "start_date", "end_date", "get_status_display", "created_at")
|
|
list_filter = ("status", "start_date", "end_date", "created_at")
|
|
search_fields = ("student__name", "message")
|
|
readonly_fields = ("created_at", "updated_at")
|
|
ordering = ("-created_at",)
|
|
raw_id_fields = ("student",)
|
|
|
|
|
|
@admin.register(StudentFeedback, site=custom_admin_site)
|
|
class StudentFeedbackAdmin(admin.ModelAdmin):
|
|
list_display = ("student", "rating", "created_at")
|
|
list_filter = ("rating", "created_at")
|
|
search_fields = ("student__name", "feedback_text")
|
|
readonly_fields = ("created_at", "updated_at")
|
|
ordering = ("-created_at",)
|
|
|
|
|
|
@admin.register(CourseTracking, site=custom_admin_site)
|
|
class CourseTrackingAdmin(admin.ModelAdmin):
|
|
list_display = (
|
|
"student",
|
|
"course",
|
|
"progress_status",
|
|
"completion_percentage",
|
|
"start_date",
|
|
"expected_end_date",
|
|
)
|
|
list_filter = ("progress_status", "course", "start_date", "expected_end_date")
|
|
search_fields = ("student__name", "course__name", "notes")
|
|
readonly_fields = ("enrollment_date", "created_at", "updated_at")
|
|
ordering = ("-created_at",)
|
|
raw_id_fields = ("student", "course")
|
|
list_per_page = 25
|
|
|
|
def has_view_permission(self, request, obj=None):
|
|
return request.user.has_perm("app.view_coursetracking")
|
|
|
|
def has_add_permission(self, request):
|
|
return request.user.has_perm("app.add_coursetracking")
|
|
|
|
def has_change_permission(self, request, obj=None):
|
|
return request.user.has_perm("app.change_coursetracking")
|
|
|
|
def has_delete_permission(self, request, obj=None):
|
|
return request.user.has_perm("app.delete_coursetracking")
|
|
|
|
def has_module_permission(self, request):
|
|
return request.user.has_module_perms("app")
|
|
|
|
|
|
@admin.register(InstituteFeedback, site=custom_admin_site)
|
|
class InstituteFeedbackAdmin(admin.ModelAdmin):
|
|
list_display = (
|
|
"display_name",
|
|
"institute",
|
|
"feedback_type",
|
|
"rating",
|
|
"is_anonymous",
|
|
"is_public",
|
|
"created_at",
|
|
)
|
|
list_filter = (
|
|
"feedback_type",
|
|
"rating",
|
|
"is_anonymous",
|
|
"is_public",
|
|
"created_at",
|
|
"institute",
|
|
)
|
|
search_fields = ("user__name", "institute__name", "feedback_text")
|
|
readonly_fields = ("created_at", "updated_at")
|
|
date_hierarchy = "created_at"
|
|
|
|
def display_name(self, obj):
|
|
return obj.display_name
|
|
|
|
display_name.short_description = "Student Name"
|
|
|
|
fieldsets = (
|
|
(None, {"fields": ("institute", "user")}),
|
|
(
|
|
"Feedback Details",
|
|
{
|
|
"fields": (
|
|
"feedback_type",
|
|
"rating",
|
|
"feedback_text",
|
|
"is_anonymous",
|
|
"is_public",
|
|
)
|
|
},
|
|
),
|
|
(
|
|
"Metadata",
|
|
{"fields": ("created_at", "updated_at"), "classes": ("collapse",)},
|
|
),
|
|
)
|
|
|
|
def get_queryset(self, request):
|
|
return super().get_queryset(request).select_related("user", "institute")
|
|
|
|
class Media:
|
|
css = {"all": ("admin/css/forms.css",)}
|
|
js = ("admin/js/collapse.js",)
|
|
|
|
|
|
@admin.register(StaffInstituteFeedback, site=custom_admin_site)
|
|
class StaffInstituteFeedbackAdmin(admin.ModelAdmin):
|
|
list_display = (
|
|
"display_name",
|
|
"institute",
|
|
"feedback_type",
|
|
"rating",
|
|
"is_anonymous",
|
|
"is_public",
|
|
"created_at",
|
|
)
|
|
list_filter = (
|
|
"feedback_type",
|
|
"rating",
|
|
"is_anonymous",
|
|
"is_public",
|
|
"created_at",
|
|
"institute",
|
|
)
|
|
search_fields = ("staff__name", "institute__name", "feedback_text")
|
|
readonly_fields = ("created_at", "updated_at")
|
|
date_hierarchy = "created_at"
|
|
|
|
def display_name(self, obj):
|
|
return obj.display_name
|
|
|
|
display_name.short_description = "Staff Name"
|
|
|
|
fieldsets = (
|
|
(None, {"fields": ("institute", "staff")}),
|
|
(
|
|
"Feedback Details",
|
|
{
|
|
"fields": (
|
|
"feedback_type",
|
|
"rating",
|
|
"feedback_text",
|
|
"is_anonymous",
|
|
"is_public",
|
|
)
|
|
},
|
|
),
|
|
(
|
|
"Metadata",
|
|
{"fields": ("created_at", "updated_at"), "classes": ("collapse",)},
|
|
),
|
|
)
|
|
|
|
def get_queryset(self, request):
|
|
return super().get_queryset(request).select_related("staff", "institute")
|
|
|
|
|
|
@admin.register(FCMDevice, site=custom_admin_site)
|
|
class FCMDeviceAdmin(admin.ModelAdmin):
|
|
list_display = ("id", "token", "created_at", "last_active", "is_active")
|
|
search_fields = ("token",)
|
|
list_filter = ("is_active", "created_at", "last_active")
|
|
readonly_fields = ("created_at", "last_active")
|
|
ordering = ("-last_active",)
|
|
|
|
fieldsets = (
|
|
(None, {"fields": ("token", "is_active")}),
|
|
("Metadata", {"fields": ("created_at", "last_active"), "classes": ("collapse",)}),
|
|
)
|
|
|
|
|
|
@admin.register(SubjectFile, site=custom_admin_site)
|
|
class SubjectFileAdmin(admin.ModelAdmin):
|
|
list_display = ("id", "title", "subject", "uploaded_by", "uploaded_at")
|
|
search_fields = ("title", "subject__name", "uploaded_by__name")
|
|
list_filter = ("subject__course", "uploaded_at")
|
|
autocomplete_fields = ["subject", "uploaded_by"]
|
|
|
|
|
|
custom_admin_site.register(User, UserAdmin)
|
|
custom_admin_site.register(Group, GroupAdmin)
|