feat(lms): add deadlines and manual assignment closing logic
This commit is contained in:
+2
-2
@@ -18,9 +18,9 @@ class QuestionInline(StackedInline):
|
|||||||
|
|
||||||
@admin.register(Assignment)
|
@admin.register(Assignment)
|
||||||
class AssignmentAdmin(ModelAdmin):
|
class AssignmentAdmin(ModelAdmin):
|
||||||
list_display = ('title', 'subject', 'is_published', 'created_at')
|
list_display = ('title', 'subject', 'is_published', 'is_closed', 'deadline', 'created_at')
|
||||||
list_display_links = ('title',)
|
list_display_links = ('title',)
|
||||||
list_filter = ('subject', 'is_published')
|
list_filter = ('subject', 'is_published', 'is_closed')
|
||||||
search_fields = ('title', 'description')
|
search_fields = ('title', 'description')
|
||||||
exclude = ('created_by',)
|
exclude = ('created_by',)
|
||||||
filter_horizontal = ('assigned_students',)
|
filter_horizontal = ('assigned_students',)
|
||||||
|
|||||||
@@ -22,6 +22,8 @@ class Assignment(models.Model):
|
|||||||
assigned_students = models.ManyToManyField(settings.AUTH_USER_MODEL, related_name='assigned_assignments', verbose_name='Назначенные ученики', blank=True, limit_choices_to={'role': 'STUDENT'}, help_text='Выберите учеников, если задание не для всех.')
|
assigned_students = models.ManyToManyField(settings.AUTH_USER_MODEL, related_name='assigned_assignments', verbose_name='Назначенные ученики', blank=True, limit_choices_to={'role': 'STUDENT'}, help_text='Выберите учеников, если задание не для всех.')
|
||||||
created_by = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, limit_choices_to={'role__in': ['TEACHER', 'ADMIN']}, verbose_name='Кем создано')
|
created_by = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, limit_choices_to={'role__in': ['TEACHER', 'ADMIN']}, verbose_name='Кем создано')
|
||||||
created_at = models.DateTimeField('Дата создания', auto_now_add=True)
|
created_at = models.DateTimeField('Дата создания', auto_now_add=True)
|
||||||
|
deadline = models.DateTimeField('Дедлайн', blank=True, null=True, help_text='После этого времени ответы не принимаются.')
|
||||||
|
is_closed = models.BooleanField('Прием ответов закрыт', default=False, help_text='Включите, чтобы вручную закрыть прием ответов на задание.')
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
verbose_name = 'Задание'
|
verbose_name = 'Задание'
|
||||||
|
|||||||
@@ -94,6 +94,11 @@
|
|||||||
</div>
|
</div>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</div>
|
</div>
|
||||||
|
{% elif not can_submit %}
|
||||||
|
<div class="mb-6 p-4 rounded-lg border bg-red-50 text-red-800 border-red-200">
|
||||||
|
<h4 class="font-bold mb-2">Прием ответов завершен</h4>
|
||||||
|
<p>Вы больше не можете отправлять ответы, так как дедлайн истек или преподаватель закрыл задание.</p>
|
||||||
|
</div>
|
||||||
{% else %}
|
{% else %}
|
||||||
<form method="post" enctype="multipart/form-data" class="space-y-6">
|
<form method="post" enctype="multipart/form-data" class="space-y-6">
|
||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
|
|||||||
@@ -51,6 +51,18 @@
|
|||||||
<span class="material-icons text-[14px]">event</span>
|
<span class="material-icons text-[14px]">event</span>
|
||||||
Добавлено: {{ assignment.created_at|date:"d M Y" }}
|
Добавлено: {{ assignment.created_at|date:"d M Y" }}
|
||||||
</span>
|
</span>
|
||||||
|
{% if assignment.deadline %}
|
||||||
|
<span class="flex items-center gap-1 {% if assignment.is_closed or assignment.deadline < now %}text-red-500{% else %}text-gray-500{% endif %}">
|
||||||
|
<span class="material-icons text-[14px]">timer</span>
|
||||||
|
Дедлайн: {{ assignment.deadline|date:"d M Y, H:i" }}
|
||||||
|
</span>
|
||||||
|
{% endif %}
|
||||||
|
{% if assignment.is_closed %}
|
||||||
|
<span class="flex items-center gap-1 text-red-500 font-medium mt-1">
|
||||||
|
<span class="material-icons text-[14px]">lock</span>
|
||||||
|
Прием ответов закрыт
|
||||||
|
</span>
|
||||||
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="bg-gray-50 p-4 border-t border-gray-100">
|
<div class="bg-gray-50 p-4 border-t border-gray-100">
|
||||||
|
|||||||
+14
-2
@@ -44,10 +44,12 @@ def dashboard(request):
|
|||||||
submissions = Submission.objects.filter(student=request.user)
|
submissions = Submission.objects.filter(student=request.user)
|
||||||
submitted_assignment_ids = submissions.values_list('assignment_id', flat=True)
|
submitted_assignment_ids = submissions.values_list('assignment_id', flat=True)
|
||||||
|
|
||||||
|
from django.utils import timezone
|
||||||
return render(request, 'lms/dashboard.html', {
|
return render(request, 'lms/dashboard.html', {
|
||||||
'assignments': assignments,
|
'assignments': assignments,
|
||||||
'submitted_assignment_ids': submitted_assignment_ids,
|
'submitted_assignment_ids': submitted_assignment_ids,
|
||||||
'submissions': {sub.assignment_id: sub for sub in submissions}
|
'submissions': {sub.assignment_id: sub for sub in submissions},
|
||||||
|
'now': timezone.now()
|
||||||
})
|
})
|
||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
@@ -58,6 +60,13 @@ def assignment_detail(request, pk):
|
|||||||
|
|
||||||
# Try to get existing submission
|
# Try to get existing submission
|
||||||
submission = Submission.objects.filter(assignment=assignment, student=request.user).first()
|
submission = Submission.objects.filter(assignment=assignment, student=request.user).first()
|
||||||
|
|
||||||
|
from django.utils import timezone
|
||||||
|
can_submit = True
|
||||||
|
if assignment.is_closed:
|
||||||
|
can_submit = False
|
||||||
|
if assignment.deadline and timezone.now() > assignment.deadline:
|
||||||
|
can_submit = False
|
||||||
|
|
||||||
if submission:
|
if submission:
|
||||||
if request.method == 'POST':
|
if request.method == 'POST':
|
||||||
@@ -65,7 +74,9 @@ def assignment_detail(request, pk):
|
|||||||
return redirect('lms:dashboard')
|
return redirect('lms:dashboard')
|
||||||
form = None
|
form = None
|
||||||
else:
|
else:
|
||||||
if request.method == 'POST':
|
if not can_submit:
|
||||||
|
form = None
|
||||||
|
elif request.method == 'POST':
|
||||||
form = AnswersForm(request.POST, request.FILES, questions=questions)
|
form = AnswersForm(request.POST, request.FILES, questions=questions)
|
||||||
if form.is_valid():
|
if form.is_valid():
|
||||||
submission = Submission.objects.create(assignment=assignment, student=request.user)
|
submission = Submission.objects.create(assignment=assignment, student=request.user)
|
||||||
@@ -153,4 +164,5 @@ def assignment_detail(request, pk):
|
|||||||
'submission': submission,
|
'submission': submission,
|
||||||
'questions': questions,
|
'questions': questions,
|
||||||
'question_fields': question_fields,
|
'question_fields': question_fields,
|
||||||
|
'can_submit': can_submit,
|
||||||
})
|
})
|
||||||
|
|||||||
Reference in New Issue
Block a user