Change live notification to polling

This commit is contained in:
cuom1999 2021-10-16 17:40:02 -05:00
parent 2539b3e071
commit 425354a2de
7 changed files with 70 additions and 58 deletions

View file

@ -1,4 +1,5 @@
from chat_box.views import ChatView, delete_message, post_message, chat_message_ajax, online_status_ajax from chat_box.views import ChatView, delete_message, post_message, chat_message_ajax, online_status_ajax
from django.conf import settings from django.conf import settings
from django.conf.urls import include, url from django.conf.urls import include, url
from django.contrib import admin from django.contrib import admin
@ -226,6 +227,7 @@ urlpatterns = [
name='contest_participation_disqualify'), name='contest_participation_disqualify'),
url(r'^/clarification$', contests.NewContestClarificationView.as_view(), name='new_contest_clarification'), 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]))), url(r'^/$', lambda _, contest: HttpResponsePermanentRedirect(reverse('contest_view', args=[contest]))),
])), ])),

View file

@ -11,9 +11,7 @@ from django.db.models.functions import Coalesce
from django.urls import reverse from django.urls import reverse
from django.utils.functional import cached_property from django.utils.functional import cached_property
from django.utils.translation import gettext_lazy as _ 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.fulltext import SearchQuerySet
from judge.models.profile import Organization, Profile from judge.models.profile import Organization, Profile
from judge.models.runtime import Language from judge.models.runtime import Language
@ -409,26 +407,6 @@ class ProblemClarification(models.Model):
description = models.TextField(verbose_name=_('clarification body')) description = models.TextField(verbose_name=_('clarification body'))
date = models.DateTimeField(verbose_name=_('clarification timestamp'), auto_now_add=True) 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): class LanguageLimit(models.Model):
problem = models.ForeignKey(Problem, verbose_name=_('problem'), related_name='language_limits', on_delete=CASCADE) problem = models.ForeignKey(Problem, verbose_name=_('problem'), related_name='language_limits', on_delete=CASCADE)

View file

@ -15,7 +15,7 @@ from django.core.exceptions import ImproperlyConfigured, ObjectDoesNotExist
from django.db import IntegrityError 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 import Case, Count, F, FloatField, IntegerField, Max, Min, Q, Sum, Value, When
from django.db.models.expressions import CombinedExpression 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.shortcuts import get_object_or_404, render
from django.template.defaultfilters import date as date_filter from django.template.defaultfilters import date as date_filter
from django.urls import reverse, reverse_lazy 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 = super(NewContestClarificationView, self).get_context_data(**kwargs)
context['problems'] = ContestProblem.objects.filter(contest=self.object)\ context['problems'] = ContestProblem.objects.filter(contest=self.object)\
.order_by('order') .order_by('order')
return context 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})

View file

@ -25,7 +25,6 @@ from django.views.generic import ListView, View
from django.views.generic.base import TemplateResponseMixin from django.views.generic.base import TemplateResponseMixin
from django.views.generic.detail import SingleObjectMixin from django.views.generic.detail import SingleObjectMixin
from judge import event_poster as event
from judge.comments import CommentedDetailView from judge.comments import CommentedDetailView
from judge.forms import ProblemCloneForm, ProblemSubmitForm from judge.forms import ProblemCloneForm, ProblemSubmitForm
from judge.models import ContestProblem, ContestSubmission, Judge, Language, Problem, ProblemGroup, \ from judge.models import ContestProblem, ContestSubmission, Judge, Language, Problem, ProblemGroup, \
@ -174,7 +173,6 @@ class ProblemDetail(ProblemMixin, SolvedProblemMixin, CommentedDetailView):
if contest_problem: if contest_problem:
clarifications = self.object.clarifications clarifications = self.object.clarifications
context['last_msg'] = event.last()
context['has_clarifications'] = clarifications.count() > 0 context['has_clarifications'] = clarifications.count() > 0
context['clarifications'] = clarifications.order_by('-date') context['clarifications'] = clarifications.order_by('-date')
context['submission_limit'] = contest_problem.max_submissions 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['hot_problems'] = hot_problems(timedelta(days=1), 7)
context['point_start'], context['point_end'], context['point_values'] = self.get_noui_slider_points() context['point_start'], context['point_end'], context['point_values'] = self.get_noui_slider_points()
else: else:
context['last_msg'] = event.last()
context['hot_problems'] = None context['hot_problems'] = None
context['point_start'], context['point_end'], context['point_values'] = 0, 0, {} context['point_start'], context['point_end'], context['point_values'] = 0, 0, {}
context['hide_contest_scoreboard'] = self.contest.scoreboard_visibility in \ context['hide_contest_scoreboard'] = self.contest.scoreboard_visibility in \

View file

@ -324,10 +324,34 @@ window.register_notify = function (type, options) {
}; };
window.notify_clarification = function(msg) { 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); 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 () { $(function () {
// Close dismissable boxes // Close dismissable boxes
$("a.close").click(function () { $("a.close").click(function () {

View file

@ -132,21 +132,6 @@
</script> </script>
{% endcompress %} {% endcompress %}
{% if request.in_contest %} {% if request.in_contest %}
{% if last_msg %}
<script type="text/javascript" src="{{ static('event.js') }}"></script>
<script>
function setup_event_contest(last_msg) {
var channel = ['contest_clarification_' + {{request.participation.contest.id}}]
return new EventReceiver(
"{{ EVENT_DAEMON_LOCATION }}", "{{ EVENT_DAEMON_POLL_LOCATION }}",
channel, last_msg, function (message) {
notify_clarification(message);
}
);
}
setup_event_contest();
</script>
{% endif %}
{% compress js %} {% compress js %}
<script src="{{ static('libs/tablesorter.js') }}" type="text/javascript"></script> <script src="{{ static('libs/tablesorter.js') }}" type="text/javascript"></script>
<script type="text/javascript"> <script type="text/javascript">
@ -174,6 +159,8 @@
return (node.hasClass('p') ? text.replace(/p$/, '') : text); return (node.hasClass('p') ? text.replace(/p$/, '') : text);
} }
}); });
window.register_contest_notification("{{url('contest_clarification_ajax', request.participation.contest.key)}}");
}); });
</script> </script>
{% endcompress %} {% endcompress %}

View file

@ -61,21 +61,9 @@
{% block content_js_media %} {% block content_js_media %}
{% include "comments/media-js.html" %} {% include "comments/media-js.html" %}
{% if request.in_contest %} {% if request.in_contest %}
{% if last_msg %} <script type="text/javascript">
<script type="text/javascript" src="{{ static('event.js') }}"></script> window.register_contest_notification("{{url('contest_clarification_ajax', request.participation.contest.key)}}");
<script> </script>
function setup_event_contest(last_msg) {
var channel = ['contest_clarification_' + {{request.participation.contest.id}}]
return new EventReceiver(
"{{ EVENT_DAEMON_LOCATION }}", "{{ EVENT_DAEMON_POLL_LOCATION }}",
channel, last_msg, function (message) {
notify_clarification(message);
}
);
}
setup_event_contest();
</script>
{% endif %}
{% endif %} {% endif %}
<script type="text/javascript"> <script type="text/javascript">
$(function() { $(function() {