You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
111 lines
4.1 KiB
111 lines
4.1 KiB
from django.contrib import admin
|
|
from django.db.models import F
|
|
from django.contrib.admin import SimpleListFilter
|
|
from django.utils.translation import gettext_lazy as _
|
|
from django import forms
|
|
|
|
from unfold.admin import ModelAdmin, StackedInline, TabularInline
|
|
from unfold.decorators import display
|
|
|
|
from apps.quiz.models import QuizParticipant, ParticipantAnswer
|
|
from apps.account.models import User
|
|
|
|
from utils.admin import project_admin_site
|
|
|
|
# --- INLINE FOR QUIZ DETAIL PAGE ---
|
|
class MinWidthInlineForm(forms.ModelForm):
|
|
def __init__(self, *args, **kwargs):
|
|
super().__init__(*args, **kwargs)
|
|
target_dropdown_fields = ['user']
|
|
for field_name, field in self.fields.items():
|
|
if field_name in target_dropdown_fields and hasattr(field.widget, 'attrs'):
|
|
existing_class = field.widget.attrs.get('class', '')
|
|
field.widget.attrs['class'] = f"{existing_class} min-w-[250px] w-full"
|
|
existing_style = field.widget.attrs.get('style', '')
|
|
field.widget.attrs['style'] = f"{existing_style} min-width: 250px; width: 250px;"
|
|
|
|
class QuizParticipantInline(TabularInline):
|
|
model = QuizParticipant
|
|
form = MinWidthInlineForm
|
|
extra = 0
|
|
tab = True
|
|
fields = ('user', 'started_at', 'total_timing', 'total_score')
|
|
readonly_fields = ('user', 'started_at', 'total_timing', 'total_score')
|
|
autocomplete_fields = ('user',)
|
|
show_change_link = True
|
|
verbose_name = _("Recent Participant")
|
|
verbose_name_plural = _("Recent Participants (Latest 10)")
|
|
|
|
def get_queryset(self, request):
|
|
qs = super().get_queryset(request)
|
|
object_id = request.resolver_match.kwargs.get('object_id')
|
|
if object_id:
|
|
latest_ids = list(qs.filter(quiz_id=object_id).order_by('-started_at').values_list('id', flat=True)[:10])
|
|
return qs.filter(id__in=latest_ids).order_by('-started_at')
|
|
return qs.none()
|
|
|
|
def has_add_permission(self, request, obj):
|
|
return False
|
|
def has_change_permission(self, request, obj=None):
|
|
return False
|
|
def has_delete_permission(self, request, obj=None):
|
|
return False
|
|
|
|
|
|
class ParticipantAnswerInline(StackedInline):
|
|
model = ParticipantAnswer
|
|
readonly_fields = (
|
|
'correct_answer_display', 'question', 'at_time', 'answer_timing',
|
|
)
|
|
|
|
@display(description=_("Correct Answer"))
|
|
|
|
def correct_answer_display(self, obj):
|
|
return obj.correct_answer
|
|
|
|
def has_add_permission(self, request, obj):
|
|
return False
|
|
|
|
def has_delete_permission(self, request, obj=None):
|
|
return False
|
|
|
|
def get_queryset(self, request):
|
|
return super().get_queryset(request).annotate(correct_answer=F('question__correct_answer'))
|
|
|
|
|
|
class UserEmailFilter(SimpleListFilter):
|
|
title = _('User Email')
|
|
parameter_name = 'user_email'
|
|
|
|
def lookups(self, request, model_admin):
|
|
# 🔔 FILTER: Only fetch active users who have an email (not guests or deleted)
|
|
users = User.objects.filter(is_active=True, email__isnull=False)
|
|
return [(user.email, user.email) for user in users]
|
|
|
|
def queryset(self, request, queryset):
|
|
if self.value():
|
|
email = self.value().replace('%40', '@')
|
|
return queryset.filter(user__email=email)
|
|
return queryset
|
|
|
|
|
|
class ParticipantAdmin(ModelAdmin):
|
|
inlines = [ParticipantAnswerInline]
|
|
search_fields = ['user__username', 'user__fullname']
|
|
list_display = [
|
|
'quiz', 'user', 'started_at', 'ended_at', 'total_timing',
|
|
'question_score', 'timing_score', 'total_score'
|
|
]
|
|
list_filter = ['started_at', 'ended_at', 'quiz__status', UserEmailFilter]
|
|
|
|
# Optional: Add these for better UI experience
|
|
date_hierarchy = 'started_at'
|
|
ordering = ['-started_at']
|
|
|
|
# 🔔 FILTER: Restrict the user dropdown in forms to active, non-guest users
|
|
def formfield_for_foreignkey(self, db_field, request, **kwargs):
|
|
if db_field.name == "user":
|
|
kwargs["queryset"] = User.objects.filter(is_active=True, email__isnull=False)
|
|
return super().formfield_for_foreignkey(db_field, request, **kwargs)
|
|
|
|
project_admin_site.register(QuizParticipant, ParticipantAdmin)
|