diff --git a/dmoj/urls.py b/dmoj/urls.py index f53b373..c5b8875 100644 --- a/dmoj/urls.py +++ b/dmoj/urls.py @@ -1,4 +1,5 @@ from chat_box.views import ChatView, delete_message, post_message, chat_message_ajax, online_status_ajax + from django.conf import settings from django.conf.urls import include, url from django.contrib import admin @@ -226,6 +227,7 @@ urlpatterns = [ name='contest_participation_disqualify'), url(r'^/clarification$', contests.NewContestClarificationView.as_view(), name='new_contest_clarification'), + url(r'^/clarification/ajax$', contests.ContestClarificationAjax.as_view(), name='contest_clarification_ajax'), url(r'^/$', lambda _, contest: HttpResponsePermanentRedirect(reverse('contest_view', args=[contest]))), ])), diff --git a/judge/models/problem.py b/judge/models/problem.py index e56b1c7..4f7e545 100644 --- a/judge/models/problem.py +++ b/judge/models/problem.py @@ -11,9 +11,7 @@ from django.db.models.functions import Coalesce from django.urls import reverse from django.utils.functional import cached_property from django.utils.translation import gettext_lazy as _ -from django.utils import timezone -from judge import event_poster as event from judge.fulltext import SearchQuerySet from judge.models.profile import Organization, Profile from judge.models.runtime import Language @@ -409,26 +407,6 @@ class ProblemClarification(models.Model): description = models.TextField(verbose_name=_('clarification body')) date = models.DateTimeField(verbose_name=_('clarification timestamp'), auto_now_add=True) - def save(self, *args, **kwargs): - super(ProblemClarification, self).save(*args, **kwargs) - - if event.real: - from judge.models import ContestProblem - - now = timezone.now() - # List all ongoing contests containing this problem - contest_problems = ContestProblem.objects.filter( - contest__start_time__lte=now, - contest__end_time__gt=now, - problem=self.problem).values_list('order', 'contest') - - for order, contest_id in contest_problems.iterator(): - event.post('contest_clarification_' + str(contest_id), { - 'problem_label': order, - 'problem_name': self.problem.name, - 'problem_code': self.problem.code, - 'body': self.description - }) class LanguageLimit(models.Model): problem = models.ForeignKey(Problem, verbose_name=_('problem'), related_name='language_limits', on_delete=CASCADE) diff --git a/judge/views/contests.py b/judge/views/contests.py index 90dc3c2..843fe04 100644 --- a/judge/views/contests.py +++ b/judge/views/contests.py @@ -15,7 +15,7 @@ from django.core.exceptions import ImproperlyConfigured, ObjectDoesNotExist from django.db import IntegrityError from django.db.models import Case, Count, F, FloatField, IntegerField, Max, Min, Q, Sum, Value, When from django.db.models.expressions import CombinedExpression -from django.http import Http404, HttpResponse, HttpResponseBadRequest, HttpResponseRedirect +from django.http import Http404, HttpResponse, HttpResponseBadRequest, HttpResponseRedirect, JsonResponse from django.shortcuts import get_object_or_404, render from django.template.defaultfilters import date as date_filter from django.urls import reverse, reverse_lazy @@ -915,4 +915,40 @@ class NewContestClarificationView(ContestMixin, TitleMixin, SingleObjectFormView context = super(NewContestClarificationView, self).get_context_data(**kwargs) context['problems'] = ContestProblem.objects.filter(contest=self.object)\ .order_by('order') - return context \ No newline at end of file + return context + + +class ContestClarificationAjax(ContestMixin, DetailView): + template_name = 'contest/clarification-ajax.html'\ + + def is_accessible(self): + if not self.request.user.is_authenticated: + return False + if not self.request.in_contest: + return False + if not self.request.participation.contest == self.object: + return False + return self.request.user.is_superuser or \ + self.request.profile in self.request.participation.contest.authors.all() or \ + self.request.profile in self.request.participation.contest.curators.all() + + def get(self, request, *args, **kwargs): + self.object = self.get_object() + if not self.is_accessible(): + raise Http404() + + polling_time = 1 # minute + last_one_minute = last_five_minutes = timezone.now()-timezone.timedelta(minutes=polling_time) + + queryset = list(ProblemClarification.objects.filter( + problem__in=self.object.problems.all(), + date__gte=last_one_minute + ).values('problem', 'problem__name', 'description')) + + problems = list(ContestProblem.objects.filter(contest=self.object)\ + .order_by('order').values('problem')) + problems = [i['problem'] for i in problems] + for cla in queryset: + cla['order'] = self.object.get_label_for_problem(problems.index(cla['problem'])) + + return JsonResponse(queryset, safe=False, json_dumps_params={'ensure_ascii': False}) diff --git a/judge/views/problem.py b/judge/views/problem.py index bfa6bb0..d039252 100644 --- a/judge/views/problem.py +++ b/judge/views/problem.py @@ -25,7 +25,6 @@ from django.views.generic import ListView, View from django.views.generic.base import TemplateResponseMixin from django.views.generic.detail import SingleObjectMixin -from judge import event_poster as event from judge.comments import CommentedDetailView from judge.forms import ProblemCloneForm, ProblemSubmitForm from judge.models import ContestProblem, ContestSubmission, Judge, Language, Problem, ProblemGroup, \ @@ -174,7 +173,6 @@ class ProblemDetail(ProblemMixin, SolvedProblemMixin, CommentedDetailView): if contest_problem: clarifications = self.object.clarifications - context['last_msg'] = event.last() context['has_clarifications'] = clarifications.count() > 0 context['clarifications'] = clarifications.order_by('-date') context['submission_limit'] = contest_problem.max_submissions @@ -437,7 +435,6 @@ class ProblemList(QueryStringSortMixin, TitleMixin, SolvedProblemMixin, ListView context['hot_problems'] = hot_problems(timedelta(days=1), 7) context['point_start'], context['point_end'], context['point_values'] = self.get_noui_slider_points() else: - context['last_msg'] = event.last() context['hot_problems'] = None context['point_start'], context['point_end'], context['point_values'] = 0, 0, {} context['hide_contest_scoreboard'] = self.contest.scoreboard_visibility in \ diff --git a/resources/common.js b/resources/common.js index 01f71b8..609a654 100644 --- a/resources/common.js +++ b/resources/common.js @@ -324,10 +324,34 @@ window.register_notify = function (type, options) { }; window.notify_clarification = function(msg) { - var message = `Problem ${msg.problem_label} (${msg.problem_name}):\n` + msg.body; + var message = `Problem ${msg.order} (${msg.problem__name}):\n` + msg.description; alert(message); } +window.register_contest_notification = function(url) { + function get_clarifications() { + $.get(url) + .fail(function() { + console.log("Fail to update clarification"); + }) + .done(function(data) { + for (i of data) { + window.notify_clarification(i); + } + if (data.status == 403) { + console.log("Fail to retrieve data"); + } + else { + $('#chat-online-content').html(data).find('.toggle').each(function () { + register_toggle($(this)); + });; + } + }) + } + get_clarifications(); + setInterval(get_clarifications, 60 * 1000); +} + $(function () { // Close dismissable boxes $("a.close").click(function () { diff --git a/templates/problem/list.html b/templates/problem/list.html index 7057d74..a79b94b 100644 --- a/templates/problem/list.html +++ b/templates/problem/list.html @@ -132,21 +132,6 @@ {% endcompress %} {% if request.in_contest %} - {% if last_msg %} - - - {% endif %} {% compress js %} {% endcompress %} diff --git a/templates/problem/problem.html b/templates/problem/problem.html index 8e67164..54b9623 100644 --- a/templates/problem/problem.html +++ b/templates/problem/problem.html @@ -61,21 +61,9 @@ {% block content_js_media %} {% include "comments/media-js.html" %} {% if request.in_contest %} - {% if last_msg %} - - - {% endif %} + {% endif %}