commit
948645efeb
6 changed files with 197 additions and 46 deletions
8
502.html
8
502.html
|
@ -1,7 +1,7 @@
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
<title>502 bad gateway - DMOJ</title>
|
<title>502 bad gateway - LQDOJ</title>
|
||||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
|
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
|
||||||
<style type="text/css">
|
<style type="text/css">
|
||||||
hr {
|
hr {
|
||||||
|
@ -49,14 +49,10 @@
|
||||||
<br>
|
<br>
|
||||||
<div class="popup">
|
<div class="popup">
|
||||||
<div>
|
<div>
|
||||||
<img class="logo" src="logo.png" alt="DMOJ">
|
<img class="logo" src="logo.png" alt="LQDOJ">
|
||||||
</div>
|
</div>
|
||||||
<h1 style="width: 100%;">Oops, LQDOJ is down now.</h1>
|
<h1 style="width: 100%;">Oops, LQDOJ is down now.</h1>
|
||||||
</div>
|
</div>
|
||||||
<br>
|
|
||||||
<hr>
|
|
||||||
<br>
|
|
||||||
<h2 class="msg">But don't worry, we'll be back soon. <br> In the free time, you can read my idol's codes <a href="http://codeforces.com/profile/cuom1999" style="color:red; text-decoration:none">cuom1999</a></h2>
|
|
||||||
</div>
|
</div>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
|
@ -31,7 +31,7 @@ from judge import event_poster as event
|
||||||
from judge.comments import CommentedDetailView
|
from judge.comments import CommentedDetailView
|
||||||
from judge.forms import ContestCloneForm
|
from judge.forms import ContestCloneForm
|
||||||
from judge.models import Contest, ContestMoss, ContestParticipation, ContestProblem, ContestTag, \
|
from judge.models import Contest, ContestMoss, ContestParticipation, ContestProblem, ContestTag, \
|
||||||
Problem, Profile, Submission
|
Organization, Problem, Profile, Submission
|
||||||
from judge.tasks import run_moss
|
from judge.tasks import run_moss
|
||||||
from judge.utils.celery import redirect_to_task_status
|
from judge.utils.celery import redirect_to_task_status
|
||||||
from judge.utils.opengraph import generate_opengraph
|
from judge.utils.opengraph import generate_opengraph
|
||||||
|
@ -81,15 +81,38 @@ class ContestList(DiggPaginatorMixin, TitleMixin, ContestListMixin, ListView):
|
||||||
template_name = 'contest/list.html'
|
template_name = 'contest/list.html'
|
||||||
title = gettext_lazy('Contests')
|
title = gettext_lazy('Contests')
|
||||||
context_object_name = 'past_contests'
|
context_object_name = 'past_contests'
|
||||||
|
first_page_href = None
|
||||||
|
|
||||||
@cached_property
|
@cached_property
|
||||||
def _now(self):
|
def _now(self):
|
||||||
return timezone.now()
|
return timezone.now()
|
||||||
|
|
||||||
|
def get(self, request, *args, **kwargs):
|
||||||
|
self.contest_query = None
|
||||||
|
self.org_query = []
|
||||||
|
|
||||||
|
if 'orgs' in self.request.GET:
|
||||||
|
try:
|
||||||
|
self.org_query = list(map(int, request.GET.getlist('orgs')))
|
||||||
|
except ValueError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
return super(ContestList, self).get(request, *args, **kwargs)
|
||||||
|
|
||||||
def _get_queryset(self):
|
def _get_queryset(self):
|
||||||
return super(ContestList, self).get_queryset() \
|
queryset = super(ContestList, self).get_queryset() \
|
||||||
.order_by('-start_time', 'key').prefetch_related('tags', 'organizations', 'organizers')
|
.order_by('-start_time', 'key').prefetch_related('tags', 'organizations', 'organizers')
|
||||||
|
|
||||||
|
if 'contest' in self.request.GET:
|
||||||
|
self.contest_query = query = ' '.join(self.request.GET.getlist('contest')).strip()
|
||||||
|
if query:
|
||||||
|
queryset = queryset.filter(
|
||||||
|
Q(key__icontains=query) | Q(name__icontains=query))
|
||||||
|
if self.org_query:
|
||||||
|
queryset = queryset.filter(organizations__in=self.org_query)
|
||||||
|
|
||||||
|
return queryset
|
||||||
|
|
||||||
def get_queryset(self):
|
def get_queryset(self):
|
||||||
return self._get_queryset().filter(end_time__lt=self._now)
|
return self._get_queryset().filter(end_time__lt=self._now)
|
||||||
|
|
||||||
|
@ -117,6 +140,12 @@ class ContestList(DiggPaginatorMixin, TitleMixin, ContestListMixin, ListView):
|
||||||
context['future_contests'] = future
|
context['future_contests'] = future
|
||||||
context['now'] = self._now
|
context['now'] = self._now
|
||||||
context['first_page_href'] = '.'
|
context['first_page_href'] = '.'
|
||||||
|
context['contest_query'] = self.contest_query
|
||||||
|
context['org_query'] = self.org_query
|
||||||
|
context['organizations'] = Organization.objects.all()
|
||||||
|
context['page_suffix'] = suffix = (
|
||||||
|
'?' + self.request.GET.urlencode()) if self.request.GET else ''
|
||||||
|
context['first_page_href'] = (self.first_page_href or '.') + suffix
|
||||||
return context
|
return context
|
||||||
|
|
||||||
|
|
||||||
|
@ -593,7 +622,8 @@ def base_contest_ranking_list(contest, problems, queryset):
|
||||||
def contest_ranking_list(contest, problems):
|
def contest_ranking_list(contest, problems):
|
||||||
return base_contest_ranking_list(contest, problems, contest.users.filter(virtual=0, user__is_unlisted=False)
|
return base_contest_ranking_list(contest, problems, contest.users.filter(virtual=0, user__is_unlisted=False)
|
||||||
.prefetch_related('user__organizations')
|
.prefetch_related('user__organizations')
|
||||||
.order_by('is_disqualified', '-score', 'cumtime'))
|
.extra(select={'round_score': 'round(score, 6)'})
|
||||||
|
.order_by('is_disqualified', '-round_score', 'cumtime'))
|
||||||
|
|
||||||
|
|
||||||
def get_contest_ranking_list(request, contest, participation=None, ranking_list=contest_ranking_list,
|
def get_contest_ranking_list(request, contest, participation=None, ranking_list=contest_ranking_list,
|
||||||
|
|
|
@ -29,7 +29,7 @@ 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, \
|
||||||
ProblemTranslation, ProblemType, RuntimeVersion, Solution, Submission, SubmissionSource, \
|
ProblemTranslation, ProblemType, RuntimeVersion, Solution, Submission, SubmissionSource, \
|
||||||
TranslatedProblemForeignKeyQuerySet
|
TranslatedProblemForeignKeyQuerySet, Organization
|
||||||
from judge.pdf_problems import DefaultPdfMaker, HAS_PDF
|
from judge.pdf_problems import DefaultPdfMaker, HAS_PDF
|
||||||
from judge.utils.diggpaginator import DiggPaginator
|
from judge.utils.diggpaginator import DiggPaginator
|
||||||
from judge.utils.opengraph import generate_opengraph
|
from judge.utils.opengraph import generate_opengraph
|
||||||
|
@ -374,6 +374,10 @@ class ProblemList(QueryStringSortMixin, TitleMixin, SolvedProblemMixin, ListView
|
||||||
if self.profile is not None and self.hide_solved:
|
if self.profile is not None and self.hide_solved:
|
||||||
queryset = queryset.exclude(id__in=Submission.objects.filter(user=self.profile, points=F('problem__points'))
|
queryset = queryset.exclude(id__in=Submission.objects.filter(user=self.profile, points=F('problem__points'))
|
||||||
.values_list('problem__id', flat=True))
|
.values_list('problem__id', flat=True))
|
||||||
|
if self.org_query:
|
||||||
|
queryset = queryset.filter(
|
||||||
|
Q(organizations__in=self.org_query) |
|
||||||
|
Q(contests__contest__organizations__in=self.org_query))
|
||||||
if self.show_types:
|
if self.show_types:
|
||||||
queryset = queryset.prefetch_related('types')
|
queryset = queryset.prefetch_related('types')
|
||||||
if self.category is not None:
|
if self.category is not None:
|
||||||
|
@ -414,12 +418,14 @@ class ProblemList(QueryStringSortMixin, TitleMixin, SolvedProblemMixin, ListView
|
||||||
context['full_text'] = 0 if self.in_contest else int(self.full_text)
|
context['full_text'] = 0 if self.in_contest else int(self.full_text)
|
||||||
context['show_editorial'] = 0 if self.in_contest else int(self.show_editorial)
|
context['show_editorial'] = 0 if self.in_contest else int(self.show_editorial)
|
||||||
|
|
||||||
|
context['organizations'] = Organization.objects.all()
|
||||||
context['category'] = self.category
|
context['category'] = self.category
|
||||||
context['categories'] = ProblemGroup.objects.all()
|
context['categories'] = ProblemGroup.objects.all()
|
||||||
if self.show_types:
|
if self.show_types:
|
||||||
context['selected_types'] = self.selected_types
|
context['selected_types'] = self.selected_types
|
||||||
context['problem_types'] = ProblemType.objects.all()
|
context['problem_types'] = ProblemType.objects.all()
|
||||||
context['has_fts'] = settings.ENABLE_FTS
|
context['has_fts'] = settings.ENABLE_FTS
|
||||||
|
context['org_query'] = self.org_query
|
||||||
context['search_query'] = self.search_query
|
context['search_query'] = self.search_query
|
||||||
context['completed_problem_ids'] = self.get_completed_problems()
|
context['completed_problem_ids'] = self.get_completed_problems()
|
||||||
context['attempted_problems'] = self.get_attempted_problems()
|
context['attempted_problems'] = self.get_attempted_problems()
|
||||||
|
@ -467,6 +473,7 @@ class ProblemList(QueryStringSortMixin, TitleMixin, SolvedProblemMixin, ListView
|
||||||
|
|
||||||
self.search_query = None
|
self.search_query = None
|
||||||
self.category = None
|
self.category = None
|
||||||
|
self.org_query = []
|
||||||
self.selected_types = []
|
self.selected_types = []
|
||||||
|
|
||||||
# This actually copies into the instance dictionary...
|
# This actually copies into the instance dictionary...
|
||||||
|
@ -481,6 +488,12 @@ class ProblemList(QueryStringSortMixin, TitleMixin, SolvedProblemMixin, ListView
|
||||||
except ValueError:
|
except ValueError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
if 'orgs' in request.GET:
|
||||||
|
try:
|
||||||
|
self.org_query = list(map(int, request.GET.getlist('orgs')))
|
||||||
|
except ValueError:
|
||||||
|
pass
|
||||||
|
|
||||||
self.point_start = safe_float_or_none(request.GET.get('point_start'))
|
self.point_start = safe_float_or_none(request.GET.get('point_start'))
|
||||||
self.point_end = safe_float_or_none(request.GET.get('point_end'))
|
self.point_end = safe_float_or_none(request.GET.get('point_end'))
|
||||||
|
|
||||||
|
|
|
@ -14,6 +14,58 @@
|
||||||
.content-description ul {
|
.content-description ul {
|
||||||
padding: 0 !important;
|
padding: 0 !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.btn-contest {
|
||||||
|
display: inline-block;
|
||||||
|
padding: 1px 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
{% if page_obj and page_obj.number > 1%}
|
||||||
|
#ongoing-table {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
@media (max-width: 500px) {
|
||||||
|
#search-contest, #search-org, #search-btn {
|
||||||
|
width: 100%;
|
||||||
|
margin-bottom: 0.5em;
|
||||||
|
}
|
||||||
|
#search-contest {
|
||||||
|
height: 2.5em;
|
||||||
|
}
|
||||||
|
#search-btn {
|
||||||
|
margin-top: 0.5em;
|
||||||
|
}
|
||||||
|
#filter-form input {
|
||||||
|
padding-left: 8px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width: 500px) {
|
||||||
|
#filter-form input {
|
||||||
|
margin: 0 0.5em 0 0!important;
|
||||||
|
padding-left: 8px;
|
||||||
|
padding-top: 8px;
|
||||||
|
}
|
||||||
|
#search-contest {
|
||||||
|
width: 30%;
|
||||||
|
height: 2.3em;
|
||||||
|
margin-right: 1em;
|
||||||
|
margin-bottom: 0;
|
||||||
|
padding-top: 4px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
#search-org {
|
||||||
|
width: 40%;
|
||||||
|
}
|
||||||
|
|
||||||
|
#search-btn {
|
||||||
|
display: inline-block;
|
||||||
|
height: 2.3em;
|
||||||
|
margin-left: 0.5em;
|
||||||
|
}
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
|
@ -32,6 +84,24 @@
|
||||||
'{{ _('Joining a contest for the first time starts your timer, after which it becomes unstoppable.') }}');
|
'{{ _('Joining a contest for the first time starts your timer, after which it becomes unstoppable.') }}');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
function makeToggleBtn(btn, divElement) {
|
||||||
|
btn.click(function() {
|
||||||
|
divElement.toggle(300);
|
||||||
|
|
||||||
|
if (btn.html().trim() === '{{ _('Hide')}}') {
|
||||||
|
btn.html('{{ _('Show')}}');
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
btn.html('{{ _('Hide')}}');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
makeToggleBtn($("#ongoing-btn"), $("#ongoing-table"));
|
||||||
|
|
||||||
|
$('#search-org').select2({multiple: 1, placeholder: '{{ _('Organizations...') }}'})
|
||||||
|
.css({'visibility': 'visible'});
|
||||||
|
|
||||||
// var tooltip_classes = 'tooltipped tooltipped-e';
|
// var tooltip_classes = 'tooltipped tooltipped-e';
|
||||||
//
|
//
|
||||||
// $('.contest-tag').each(function () {
|
// $('.contest-tag').each(function () {
|
||||||
|
@ -144,6 +214,20 @@
|
||||||
|
|
||||||
{% block body %}
|
{% block body %}
|
||||||
<div class="content-description">
|
<div class="content-description">
|
||||||
|
|
||||||
|
<form id="filter-form">
|
||||||
|
<input id="search-contest" type="text" name="contest" value="{{ contest_query or '' }}"
|
||||||
|
placeholder="{{ _('Search contests...') }}">
|
||||||
|
|
||||||
|
<select id="search-org" name="orgs" multiple>
|
||||||
|
{% for org in organizations %}
|
||||||
|
<option value="{{ org.id }}"{% if org.id in org_query %} selected{% endif %}>
|
||||||
|
{{ org.name }}
|
||||||
|
</option>
|
||||||
|
{% endfor %}
|
||||||
|
</select>
|
||||||
|
<button id="search-btn"> {{ _('Search')}} </button>
|
||||||
|
</form>
|
||||||
{% if active_participations %}
|
{% if active_participations %}
|
||||||
<h4>{{ _('Active Contests') }}</h4>
|
<h4>{{ _('Active Contests') }}</h4>
|
||||||
<table class="contest-list table striped">
|
<table class="contest-list table striped">
|
||||||
|
@ -187,41 +271,52 @@
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
{% if current_contests %}
|
{% if current_contests %}
|
||||||
<h4>{{ _('Ongoing Contests') }}</h4>
|
<h4>
|
||||||
<table class="contest-list table striped">
|
{{ _('Ongoing Contests') }}
|
||||||
<thead>
|
<button class="btn-contest" id="ongoing-btn">
|
||||||
<tr>
|
{% if page_obj and page_obj.number > 1%}
|
||||||
<th style="width:90%">{{ _('Contest') }}</th>
|
{{_('Show')}}
|
||||||
<th>{{ _('Users') }}</th>
|
{% else %}
|
||||||
{% if not request.in_contest %}
|
{{_('Hide')}}
|
||||||
<th style="width:15%"></th>
|
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</tr>
|
</button>
|
||||||
</thead>
|
</h4>
|
||||||
<tbody>
|
<div id="ongoing-table">
|
||||||
{% for contest in current_contests %}
|
<table class="contest-list table striped">
|
||||||
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<td>
|
<th style="width:90%">{{ _('Contest') }}</th>
|
||||||
<div class="contest-block">
|
<th>{{ _('Users') }}</th>
|
||||||
{{ contest_head(contest) }}
|
{% if not request.in_contest %}
|
||||||
{% if contest.start_time %}
|
<th style="width:15%"></th>
|
||||||
<br>
|
{% endif %}
|
||||||
{% if contest.time_before_end %}
|
|
||||||
<span class="time">{{ _('Ends in %(countdown)s', countdown=contest.time_before_end|as_countdown) }}</span>
|
|
||||||
{% endif %}
|
|
||||||
{{ time_left(contest) }}
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
{{ user_count(contest, request.user) }}
|
|
||||||
</td>
|
|
||||||
{{ contest_join(contest, request) }}
|
|
||||||
</tr>
|
</tr>
|
||||||
{% endfor %}
|
</thead>
|
||||||
</tbody>
|
<tbody>
|
||||||
</table>
|
{% for contest in current_contests %}
|
||||||
<br>
|
<tr>
|
||||||
|
<td>
|
||||||
|
<div class="contest-block">
|
||||||
|
{{ contest_head(contest) }}
|
||||||
|
{% if contest.start_time %}
|
||||||
|
<br>
|
||||||
|
{% if contest.time_before_end %}
|
||||||
|
<span class="time">{{ _('Ends in %(countdown)s', countdown=contest.time_before_end|as_countdown) }}</span>
|
||||||
|
{% endif %}
|
||||||
|
{{ time_left(contest) }}
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
{{ user_count(contest, request.user) }}
|
||||||
|
</td>
|
||||||
|
{{ contest_join(contest, request) }}
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
<br>
|
||||||
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
<h4>{{ _('Upcoming Contests') }}</h4>
|
<h4>{{ _('Upcoming Contests') }}</h4>
|
||||||
|
|
|
@ -3,13 +3,17 @@
|
||||||
{% block media %}
|
{% block media %}
|
||||||
<link rel="stylesheet" href="{{ static('libs/nouislider.min.css') }}">
|
<link rel="stylesheet" href="{{ static('libs/nouislider.min.css') }}">
|
||||||
<noscript>
|
<noscript>
|
||||||
<style>#category, #types {
|
<style>
|
||||||
visibility: visible;
|
#category, #types {
|
||||||
}
|
visibility: visible;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
</noscript>
|
</noscript>
|
||||||
{% if not request.in_contest %}
|
{% if not request.in_contest %}
|
||||||
<style>
|
<style>
|
||||||
|
#search-org {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
#problem-table th {
|
#problem-table th {
|
||||||
padding: 0;
|
padding: 0;
|
||||||
}
|
}
|
||||||
|
@ -61,6 +65,8 @@
|
||||||
$category.select2().css({'visibility': 'visible'}).change(clean_submit);
|
$category.select2().css({'visibility': 'visible'}).change(clean_submit);
|
||||||
$('#types').select2({multiple: 1, placeholder: '{{ _('Filter by type...') }}'})
|
$('#types').select2({multiple: 1, placeholder: '{{ _('Filter by type...') }}'})
|
||||||
.css({'visibility': 'visible'});
|
.css({'visibility': 'visible'});
|
||||||
|
$('#search-org').select2({multiple: 1, placeholder: '{{ _('Organizations...') }}'})
|
||||||
|
.css({'visibility': 'visible'});
|
||||||
|
|
||||||
// This is incredibly nasty to do but it's needed because otherwise the select2 steals the focus
|
// This is incredibly nasty to do but it's needed because otherwise the select2 steals the focus
|
||||||
$search.keypress(function (e) {
|
$search.keypress(function (e) {
|
||||||
|
|
|
@ -31,6 +31,16 @@
|
||||||
{% if show_editorial %} checked{% endif %}>
|
{% if show_editorial %} checked{% endif %}>
|
||||||
<label for="show_editorial">{{ _('Show editorial') }}</label>
|
<label for="show_editorial">{{ _('Show editorial') }}</label>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="filter-form-group">
|
||||||
|
<label for="type"><i>{{ _('Organization') }}</i></label>
|
||||||
|
<select id="search-org" name="orgs" multiple>
|
||||||
|
{% for org in organizations %}
|
||||||
|
<option value="{{ org.id }}"{% if org.id in org_query %} selected{% endif %}>
|
||||||
|
{{ org.name }}
|
||||||
|
</option>
|
||||||
|
{% endfor %}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
<div class="filter-form-group">
|
<div class="filter-form-group">
|
||||||
<label for="category"><i>{{ _('Category') }}</i></label>
|
<label for="category"><i>{{ _('Category') }}</i></label>
|
||||||
<select id="category" name="category">
|
<select id="category" name="category">
|
||||||
|
@ -45,6 +55,7 @@
|
||||||
</option>
|
</option>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
{% if show_types %}
|
{% if show_types %}
|
||||||
<div class="filter-form-group">
|
<div class="filter-form-group">
|
||||||
|
|
Loading…
Reference in a new issue