Change live notification to polling
This commit is contained in:
parent
2539b3e071
commit
425354a2de
7 changed files with 70 additions and 58 deletions
|
@ -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]))),
|
||||
])),
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
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})
|
||||
|
|
|
@ -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 \
|
||||
|
|
|
@ -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 () {
|
||||
|
|
|
@ -132,21 +132,6 @@
|
|||
</script>
|
||||
{% endcompress %}
|
||||
{% 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 %}
|
||||
<script src="{{ static('libs/tablesorter.js') }}" type="text/javascript"></script>
|
||||
<script type="text/javascript">
|
||||
|
@ -174,6 +159,8 @@
|
|||
return (node.hasClass('p') ? text.replace(/p$/, '') : text);
|
||||
}
|
||||
});
|
||||
|
||||
window.register_contest_notification("{{url('contest_clarification_ajax', request.participation.contest.key)}}");
|
||||
});
|
||||
</script>
|
||||
{% endcompress %}
|
||||
|
|
|
@ -61,21 +61,9 @@
|
|||
{% block content_js_media %}
|
||||
{% include "comments/media-js.html" %}
|
||||
{% 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 %}
|
||||
<script type="text/javascript">
|
||||
window.register_contest_notification("{{url('contest_clarification_ajax', request.participation.contest.key)}}");
|
||||
</script>
|
||||
{% endif %}
|
||||
<script type="text/javascript">
|
||||
$(function() {
|
||||
|
|
Loading…
Reference in a new issue