Rewrite org page

This commit is contained in:
cuom1999 2022-05-27 23:28:22 -05:00
parent 05ff359f89
commit 82ec9e098d
22 changed files with 1190 additions and 777 deletions

View file

@ -587,6 +587,16 @@ urlpatterns = [
organization.OrganizationUsers.as_view(),
name="organization_users",
),
url(
r"^/problems$",
organization.OrganizationProblems.as_view(),
name="organization_problems",
),
url(
r"^/contests$",
organization.OrganizationContests.as_view(),
name="organization_contests",
),
url(
r"^/join$",
organization.JoinOrganization.as_view(),

View file

@ -106,6 +106,12 @@ class Organization(models.Model):
def get_users_url(self):
return reverse("organization_users", args=(self.id, self.slug))
def get_problems_url(self):
return reverse("organization_problems", args=(self.id, self.slug))
def get_contests_url(self):
return reverse("organization_contests", args=(self.id, self.slug))
class Meta:
ordering = ["name"]
permissions = (

View file

@ -69,31 +69,15 @@ class FeedView(ListView):
now = timezone.now()
# Dashboard stuff
# if self.request.user.is_authenticated:
# user = self.request.profile
# context['recently_attempted_problems'] = (Submission.objects.filter(user=user)
# .exclude(problem__in=user_completed_ids(user))
# .values_list('problem__code', 'problem__name', 'problem__points')
# .annotate(points=Max('points'), latest=Max('date'))
# .order_by('-latest')
# [:settings.DMOJ_BLOG_RECENTLY_ATTEMPTED_PROBLEMS_COUNT])
visible_contests = (
Contest.get_visible_contests(self.request.user)
.filter(is_visible=True)
.order_by("start_time")
)
context["current_contests"] = visible_contests.filter(
start_time__lte=now, end_time__gt=now
)
context["future_contests"] = visible_contests.filter(start_time__gt=now)
visible_contests = Contest.get_visible_contests(self.request.user).filter(
is_visible=True
)
context["top_rated"] = Profile.objects.filter(is_unlisted=False).order_by(
"-rating"
)[:10]

View file

@ -146,9 +146,15 @@ class ContestList(
self.contest_query = None
self.org_query = []
if "orgs" in self.request.GET:
if "orgs" in self.request.GET and self.request.profile:
try:
self.org_query = list(map(int, request.GET.getlist("orgs")))
self.org_query = [
i
for i in self.org_query
if i
in self.request.profile.organizations.values_list("id", flat=True)
]
except ValueError:
pass
@ -215,7 +221,9 @@ class ContestList(
context["first_page_href"] = "."
context["contest_query"] = self.contest_query
context["org_query"] = self.org_query
context["organizations"] = Organization.objects.all()
if self.request.profile:
context["organizations"] = self.request.profile.organizations.all()
context["page_type"] = "list"
context.update(self.get_sort_context())
context.update(self.get_sort_paginate_context())
return context

View file

@ -7,8 +7,14 @@ from django.core.cache.utils import make_template_fragment_key
from django.core.exceptions import PermissionDenied
from django.db import transaction
from django.db.models import Count, Q, Value, BooleanField
from django.db.utils import ProgrammingError
from django.forms import Form, modelformset_factory
from django.http import Http404, HttpResponsePermanentRedirect, HttpResponseRedirect
from django.http import (
Http404,
HttpResponsePermanentRedirect,
HttpResponseRedirect,
HttpResponseBadRequest,
)
from django.urls import reverse
from django.utils import timezone
from django.utils.safestring import mark_safe
@ -18,6 +24,7 @@ from django.views.generic.detail import (
SingleObjectMixin,
SingleObjectTemplateResponseMixin,
)
from django.core.paginator import Paginator
from reversion import revisions
from judge.forms import EditOrganizationForm
@ -37,11 +44,15 @@ from judge.utils.views import (
QueryStringSortMixin,
DiggPaginatorMixin,
)
from judge.views.problem import ProblemList
from judge.views.contests import ContestList
__all__ = [
"OrganizationList",
"OrganizationHome",
"OrganizationUsers",
"OrganizationProblems",
"OrganizationContests",
"OrganizationMembershipChange",
"JoinOrganization",
"LeaveOrganization",
@ -111,6 +122,12 @@ class OrganizationDetailView(OrganizationMixin, DetailView):
context = self.get_context_data(object=self.object)
return self.render_to_response(context)
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context["can_edit"] = self.can_edit_organization()
context["is_member"] = self.is_member()
return context
class OrganizationList(TitleMixin, ListView, OrganizationBase):
model = Organization
@ -139,19 +156,8 @@ class OrganizationList(TitleMixin, ListView, OrganizationBase):
class OrganizationHome(OrganizationDetailView):
template_name = "organization/home.html"
def get_context_data(self, **kwargs):
context = super(OrganizationHome, self).get_context_data(**kwargs)
context["title"] = self.object.name
context["can_edit"] = self.can_edit_organization()
context["is_member"] = self.is_member()
context["new_problems"] = Problem.objects.filter(
is_public=True, is_organization_private=True, organizations=self.object
).order_by("-date", "-id")[: settings.DMOJ_BLOG_NEW_PROBLEM_COUNT]
context["new_contests"] = Contest.objects.filter(
is_visible=True, is_organization_private=True, organizations=self.object
).order_by("-end_time", "-id")[: settings.DMOJ_BLOG_NEW_CONTEST_COUNT]
context["posts"] = (
def get_posts(self):
posts = (
BlogPost.objects.filter(
visible=True,
publish_on__lte=timezone.now(),
@ -161,6 +167,21 @@ class OrganizationHome(OrganizationDetailView):
.order_by("-sticky", "-publish_on")
.prefetch_related("authors__user", "organizations")
)
paginator = Paginator(posts, 10)
page_number = self.request.GET.get("page", 1)
posts = paginator.get_page(page_number)
return posts
def get_context_data(self, **kwargs):
context = super(OrganizationHome, self).get_context_data(**kwargs)
context["title"] = self.object.name
context["new_problems"] = Problem.objects.filter(
is_public=True, is_organization_private=True, organizations=self.object
).order_by("-date", "-id")[: settings.DMOJ_BLOG_NEW_PROBLEM_COUNT]
context["new_contests"] = Contest.objects.filter(
is_visible=True, is_organization_private=True, organizations=self.object
).order_by("-end_time", "-id")[: settings.DMOJ_BLOG_NEW_CONTEST_COUNT]
context["posts"] = self.get_posts()
context["post_comment_counts"] = {
int(page[2:]): count
for page, count in Comment.objects.filter(
@ -173,6 +194,26 @@ class OrganizationHome(OrganizationDetailView):
context["pending_count"] = OrganizationRequest.objects.filter(
state="P", organization=self.object
).count()
now = timezone.now()
visible_contests = (
Contest.get_visible_contests(self.request.user)
.filter(
is_visible=True, is_organization_private=True, organizations=self.object
)
.order_by("start_time")
)
context["current_contests"] = visible_contests.filter(
start_time__lte=now, end_time__gt=now
)
context["future_contests"] = visible_contests.filter(start_time__gt=now)
context["top_rated"] = self.object.members.filter(is_unlisted=False).order_by(
"-rating"
)[:10]
context["top_scorer"] = self.object.members.filter(is_unlisted=False).order_by(
"-performance_points"
)[:10]
context["page_type"] = "home"
return context
@ -186,7 +227,7 @@ class OrganizationUsers(QueryStringSortMixin, OrganizationDetailView):
context = super(OrganizationUsers, self).get_context_data(**kwargs)
context["title"] = _("%s Members") % self.object.name
context["partial"] = True
context["is_admin"] = self.can_edit_organization()
context["can_edit"] = self.can_edit_organization()
context["kick_url"] = reverse(
"organization_user_kick", args=[self.object.id, self.object.slug]
)
@ -206,10 +247,76 @@ class OrganizationUsers(QueryStringSortMixin, OrganizationDetailView):
)
)
context["first_page_href"] = "."
context["page_type"] = "users"
context.update(self.get_sort_context())
return context
class OrganizationExternalMixin(OrganizationBase):
organization_id = None
organization = None
def get_organization_from_url(self, request, *args, **kwargs):
try:
self.organization_id = int(kwargs["pk"])
self.organization = Organization.objects.get(id=self.organization_id)
except:
return HttpResponseBadRequest()
if self.organization.slug != kwargs["slug"]:
return HttpResponsePermanentRedirect(
request.get_full_path().replace(kwargs["slug"], self.object.slug)
)
return None
def edit_context_data(self, context):
context["is_member"] = self.is_member(self.organization)
context["can_edit"] = self.can_edit_organization(self.organization)
context["organization"] = self.organization
context["logo_override_image"] = self.organization.logo_override_image
context.pop("organizations")
class OrganizationProblems(ProblemList, OrganizationExternalMixin):
template_name = "organization/problems.html"
def get_queryset(self):
self.org_query = [self.organization_id]
return super().get_normal_queryset()
def get(self, request, *args, **kwargs):
ret = super().get_organization_from_url(request, *args, **kwargs)
if ret:
return ret
self.setup_problem_list(request)
return super().get(request, *args, **kwargs)
def get_context_data(self, **kwargs):
context = super(OrganizationProblems, self).get_context_data(**kwargs)
self.edit_context_data(context)
context["page_type"] = "problems"
return context
class OrganizationContests(ContestList, OrganizationExternalMixin):
template_name = "organization/contests.html"
def get_queryset(self):
self.org_query = [self.organization_id]
return super().get_queryset()
def get(self, request, *args, **kwargs):
ret = super().get_organization_from_url(request, *args, **kwargs)
if ret:
return ret
return super().get(request, *args, **kwargs)
def get_context_data(self, **kwargs):
context = super(OrganizationContests, self).get_context_data(**kwargs)
self.edit_context_data(context)
context["page_type"] = "contests"
return context
class OrganizationMembershipChange(
LoginRequiredMixin, OrganizationMixin, SingleObjectMixin, View
):

View file

@ -567,6 +567,13 @@ class ProblemList(QueryStringSortMixin, TitleMixin, SolvedProblemMixin, ListView
)
]
def get_org_query(self, query):
return [
i
for i in query
if i in self.profile.organizations.values_list("id", flat=True)
]
def get_normal_queryset(self):
filter = Q(is_public=True)
if self.profile is not None:
@ -588,6 +595,7 @@ class ProblemList(QueryStringSortMixin, TitleMixin, SolvedProblemMixin, ListView
).values_list("problem__id", flat=True)
)
if self.org_query:
self.org_query = self.get_org_query(self.org_query)
queryset = queryset.filter(
Q(organizations__in=self.org_query)
| Q(contests__contest__organizations__in=self.org_query)
@ -650,7 +658,8 @@ class ProblemList(QueryStringSortMixin, TitleMixin, SolvedProblemMixin, ListView
context["show_editorial"] = 0 if self.in_contest else int(self.show_editorial)
context["have_editorial"] = 0 if self.in_contest else int(self.have_editorial)
context["organizations"] = Organization.objects.all()
if self.request.profile:
context["organizations"] = self.request.profile.organizations.all()
all_authors_ids = set(Problem.objects.values_list("authors", flat=True))
context["all_authors"] = Profile.objects.filter(id__in=all_authors_ids)
context["category"] = self.category
@ -702,7 +711,7 @@ class ProblemList(QueryStringSortMixin, TitleMixin, SolvedProblemMixin, ListView
("?" + self.request.GET.urlencode()) if self.request.GET else ""
)
context["first_page_href"] = (self.first_page_href or ".") + suffix
context["has_show_editorial_option"] = True
return context
def get_noui_slider_points(self):
@ -811,6 +820,7 @@ cf_logger = logging.getLogger("judge.ml.collab_filter")
class ProblemFeed(ProblemList):
model = Problem
context_object_name = "problems"
template_name = "problem/feed.html"
paginate_by = 20
title = _("Problem feed")
feed_type = None
@ -926,7 +936,8 @@ class ProblemFeed(ProblemList):
context["page_type"] = "feed"
context["title"] = self.title
context["feed_type"] = self.feed_type
context["has_show_editorial_option"] = False
context["has_have_editorial_option"] = False
return context
def get(self, request, *args, **kwargs):

View file

@ -4199,11 +4199,11 @@ msgstr "Quản lý"
#: templates/organization/home.html:135
msgid "Edit organization"
msgstr "Chỉnh sửa tổ chức"
msgstr "Chỉnh sửa"
#: templates/organization/home.html:141
msgid "View requests"
msgstr "Xem các đơn đăng ký"
msgstr "Đơn đăng ký"
#: templates/organization/home.html:154
msgid "Admin organization"

View file

@ -122,72 +122,7 @@
</div>
</div>
{% endif %}
{% if current_contests %}
<div class="blog-sidebox sidebox">
<h3>{{ _('Ongoing contests') }} <i class="fa fa-trophy"></i></h3>
<div class="sidebox-content">
{% for contest in current_contests %}
<div class="contest">
<div class="contest-list-title">
<a href="{{ url('contest_view', contest.key) }}">{{ contest.name }}</a>
</div>
<div class="time">
{{ _('Ends in') }} {{ _('%(countdown)s.', countdown=contest.end_time|as_countdown) }}
</div>
</div>
{% endfor %}
</div>
</div>
{% endif %}
{% if future_contests %}
<div class="blog-sidebox sidebox">
<h3>{{ _('Upcoming contests') }} <i class="fa fa-trophy"></i></h3>
<div class="sidebox-content">
{% for contest in future_contests %}
<div class="contest">
<div class="contest-list-title">
<a href="{{ url('contest_view', contest.key) }}">{{ contest.name }}</a>
</div>
<div class="time">
{{ _('Starting in %(countdown)s.', countdown=contest.start_time|as_countdown) }}
</div>
</div>
{% endfor %}
</div>
</div>
{% endif %}
<div class="blog-sidebox sidebox">
<h3>{{ _('Top Rating') }} <i class="fa fa-trophy"></i></h3>
<div class="sidebox-content" style="padding: 0; border: 0">
<table class="table feed-table">
<tbody>
{% for user in top_rated %}
<tr>
<td style="padding: 7px 2px"><b>{{loop.index}}</b></td>
<td>{{link_user(user)}}</td>
<td>{{user.rating}}</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
<div class="blog-sidebox sidebox">
<h3>{{ _('Top Score') }} <i class="fa fa-trophy"></i></h3>
<div class="sidebox-content" style="padding: 0; border: 0">
<table class="table feed-table">
<tbody>
{% for user in top_scorer %}
<tr>
<td style="padding: 7px 2px"><b>{{loop.index}}</b></td>
<td>{{link_user(user)}}</td>
<td>{{ user.performance_points|floatformat(0) }}</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
{% include 'contests-countdown.html' %}
{% include 'top-users.html' %}
</div>
{% endblock %}

View file

@ -1,9 +1,9 @@
{% extends "common-content.html" %}
{% extends "three-column-content.html" %}
{% block meta %}
<meta name="description" content="The {{ SITE_NAME }}'s contest list - past, present, and future.">
{% endblock %}
{% block media %}
{% block three_col_media %}
<style>
.time-left {
text-align: left;
@ -66,10 +66,17 @@
margin-left: 0.5em;
}
}
@media (min-width: 800px) {
.middle-content {
max-width: none;
padding-left: 1em;
}
}
</style>
{% endblock %}
{% block js_media %}
{% block three_col_js %}
<script src="{{ static('libs/featherlight/featherlight.min.js') }}" type="text/javascript"></script>
<script type="text/javascript">
$(document).ready(function () {
@ -116,12 +123,12 @@
</script>
{% endblock %}
{% block title_ruler %}{% endblock %}
{% block title_row %}
{% set tab = 'list' %}
{% set title = 'Contests' %}
{% include "contest/contest-list-tabs.html" %}
{% block left_sidebar %}
<div class="left-sidebar">
{{ make_tab_item('list', 'fa fa-list', url('contest_list'), _('List')) }}
{{ make_tab_item('calendar', 'fa fa-calendar', url('contest_calendar', now.year, now.month), _('Calendar')) }}
{{ make_tab_item('admin', 'fa fa-edit', url('admin:judge_contest_changelist'), _('Admin')) }}
</div>
{% endblock %}
{% macro contest_head(contest) %}
@ -212,12 +219,12 @@
{% endif %}
{% endmacro %}
{% block body %}
{% block middle_content %}
<div class="content-description">
<form id="filter-form">
<input id="search-contest" type="text" name="contest" value="{{ contest_query or '' }}"
placeholder="{{ _('Search contests...') }}">
{% if organizations %}
<select id="search-org" name="orgs" multiple>
{% for org in organizations %}
<option value="{{ org.id }}"{% if org.id in org_query %} selected{% endif %}>
@ -225,6 +232,7 @@
</option>
{% endfor %}
</select>
{% endif %}
<button id="search-btn"> {{ _('Search')}} </button>
</form>
{% if active_participations %}

View file

@ -0,0 +1,35 @@
{% if current_contests %}
<div class="blog-sidebox sidebox">
<h3>{{ _('Ongoing contests') }} <i class="fa fa-trophy"></i></h3>
<div class="sidebox-content">
{% for contest in current_contests %}
<div class="contest">
<div class="contest-list-title">
<a href="{{ url('contest_view', contest.key) }}">{{ contest.name }}</a>
</div>
<div class="time">
{{ _('Ends in') }} {{ _('%(countdown)s.', countdown=contest.end_time|as_countdown) }}
</div>
</div>
{% endfor %}
</div>
</div>
{% endif %}
{% if future_contests %}
<div class="blog-sidebox sidebox">
<h3>{{ _('Upcoming contests') }} <i class="fa fa-trophy"></i></h3>
<div class="sidebox-content">
{% for contest in future_contests %}
<div class="contest">
<div class="contest-list-title">
<a href="{{ url('contest_view', contest.key) }}">{{ contest.name }}</a>
</div>
<div class="time">
{{ _('Starting in %(countdown)s.', countdown=contest.start_time|as_countdown) }}
</div>
</div>
{% endfor %}
</div>
</div>
{% endif %}

View file

@ -0,0 +1,4 @@
{% extends "contest/list.html" %}
{% block left_sidebar %}
{% include "organization/org-left-sidebar.html" %}
{% endblock %}

View file

@ -1,12 +1,6 @@
{% extends "base.html" %}
{% block media %}
{% extends "three-column-content.html" %}
{% block three_col_media %}
<style>
{% if request.user.is_authenticated and is_member %}
#control-panel {
display: none;
}
{% endif %}
.leave-organization, .leave-organization:hover {
color: red;
}
@ -25,9 +19,12 @@
</style>
{% endblock %}
{% block js_media %}
{% block three_col_js %}
<script type="text/javascript">
$(function () {
$('.time-remaining').each(function () {
count_down($(this));
});
$('.leave-organization').click(function () {
if (confirm('{{ _('Are you sure you want to leave this organization?') }}\n' +
{% if organization.is_open %}
@ -41,32 +38,22 @@
});
$(document).ready(function () {
$('.blog-sidebar').hide();
$('#info-tab').find('a').click(function (e) {
e.preventDefault();
$('#info-tab').addClass('active');
$('#detail-tab').removeClass('active');
$('.blog-content').show();
$('.blog-sidebar').hide();
});
$('#detail-tab').find('a').click(function (e) {
e.preventDefault();
$('#detail-tab').addClass('active');
$('#info-tab').removeClass('active');
$('.blog-content').hide();
$('.blog-sidebar').show();
});
$('.control-button').click(function(e) {
e.preventDefault();
$('#control-panel').toggle("fast");
})
});
});
</script>
{% endblock %}
{% block title_row %}
{% block left_sidebar %}
{% include "organization/org-left-sidebar.html" %}
{% endblock %}
{% block title_ruler %}{% endblock %}
{% block middle_content %}
{% block before_posts %}{% endblock %}
<div class="page-title">
<div class="tabs">
<h2>{{title}}</h2>
@ -85,51 +72,51 @@
class="unselectable button">{{ _('Request membership') }}</a>
{% endif %}
{% endif %}
<button class="control-button"><i class="fa fa-ellipsis-h"></i></button>
</div>
</div>
{% endblock %}
{% block title_ruler %} {% endblock %}
{% block body %}
{% block before_posts %}{% endblock %}
<div id="mobile" class="tabs">
<ul>
<li id="info-tab" class="tab active"><a href="#">
<i class="tab-icon fa fa-info-circle"></i> {{ _('Info') }}
</a></li>
<li id="detail-tab" class="tab"><a href="#"><i class="tab-icon fa fa-rss"></i> {{ _('Details') }}</a></li>
</ul>
</div>
<div id="blog-container">
<div class="blog-content sidebox">
{% if is_member or can_edit %}
{% for post in posts %}
{% include "blog/content.html" %}
{% if posts.paginator.num_pages > 1 %}
<div style="margin-bottom:10px;margin-top:10px">{% include "list-pages.html" %}</div>
{% endif %}
{% endfor %}
{% else %}
<div class="blog-sidebox sidebox">
<h3>{{ _('About') }}<i class="fa fa-info-circle"></i></h3>
<div class="sidebox-content">
<div style="margin: 1.4em;">
<div style="margin: 0.3em;">
{% cache 3600 'organization_html' organization.id MATH_ENGINE %}
{{ organization.about|markdown('organization-about', MATH_ENGINE)|reference|str|safe }}
{% endcache %}
</div>
</div>
{% if is_member or can_edit %}
<br>
<h3>{{ _('Organization news') }} <i class="fa fa-terminal"></i></h3>
<div class="sidebox-content">
{% for post in posts %}
{% include "blog/content.html" %}
{% else %}
<div style="margin: 1.4em;">
<i>{{ _('There is no news at this time.') }}</i>
</div>
{% endfor %}
</div>
{% endif %}
</div>
{% block after_posts %}{% endblock %}
{% endblock %}
<div class="blog-sidebar">
{% block right_sidebar %}
<div class="right-sidebar">
{% if (is_member or can_edit) %}
{% include 'contests-countdown.html' %}
{% endif %}
{% if is_member or can_edit %}
<div class="blog-sidebox sidebox">
<h3>{{ _('About') }}<i class="fa fa-info-circle"></i></h3>
<div class="sidebox-content">
<div style="margin: 0.3em;">
{% cache 3600 'organization_html' organization.id MATH_ENGINE %}
{{ organization.about|markdown('organization-about', MATH_ENGINE)|reference|str|safe }}
{% endcache %}
</div>
</div>
</div>
{% endif %}
{% if can_edit %}
<div id="control-panel" class="blog-sidebox sidebox">
<h3>{{ _('Controls') }} <i class="fa fa-cog"></i></h3>
<ul id="control-list" class="sidebox-content" style="padding: 1em;">
{% if can_edit %}
<li>
<div>
<a href="{{ url('edit_organization', organization.id, organization.slug) }}">{{ _('Edit organization') }}</a>
@ -147,19 +134,6 @@
</div>
</li>
{% endif %}
{% endif %}
{% if perms.judge.change_organization %}
<li>
<div>
<a href="{{ url('admin:judge_organization_change', organization.id) }}">{{ _('Admin organization') }}</a>
</div>
</li>
{% endif %}
<li>
<div>
<a href="{{ organization.get_users_url() }}">{{ _('View members') }}</a>
</div>
</li>
{% if is_member and not can_edit %}
<li>
<form method="post" action="{{ url('leave_organization', organization.id, organization.slug) }}">
@ -170,40 +144,7 @@
{% endif %}
</ul>
</div>
{% if (is_member or can_edit) %}
{% if new_contests %}
<div class="blog-sidebox sidebox">
<h3>{{ _('New private contests') }} <i class="fa fa-trophy"></i>
</h3>
<div class="sidebox-content">
<ul class="problem-list">
{% for contest in new_contests %}
<li><a href="{{ url('contest_view', contest.key) }}">{{ contest.name }}</a></li>
{% endfor %}
</ul>
<hr>
<center><a target="_blank" href="{{url('contest_list')+'?orgs='+str(organization.id)}}">{{_('View all')}} <i class="fa fa-chevron-right"></i></a></center>
</div>
</div>
{% endif %}
{% if new_problems %}
<div class="blog-sidebox sidebox">
<h3>{{ _('New private problems') }} <i class="fa fa-puzzle-piece"></i>
</h3>
<div class="sidebox-content">
<ul class="problem-list">
{% for problem in new_problems %}
<li><a href="{{ url('problem_detail', problem.code) }}">{{ problem.name }}</a></li>
{% endfor %}
</ul>
<hr>
<center><a target="_blank" href="{{url('problem_list')+'?orgs='+str(organization.id)}}">{{_('View all')}} <i class="fa fa-chevron-right"></i></a></center>
{% include 'top-users.html' %}
</div>
</div>
{% endif %}
{% endif %}
</div>
</div>
{% block after_posts %}{% endblock %}
{% endblock %}

View file

@ -0,0 +1,11 @@
<div class="left-sidebar">
{{ make_tab_item('home', 'fa fa-home', organization.get_absolute_url(), _('Home')) }}
{% if is_member or can_edit %}
{{ make_tab_item('problems', 'fa fa-list', organization.get_problems_url(), _('Problems')) }}
{{ make_tab_item('contests', 'fa fa-trophy', organization.get_contests_url(), _('Contests')) }}
{% endif %}
{{ make_tab_item('users', 'fa fa-user', organization.get_users_url(), _('Members')) }}
{% if perms.judge.change_organization %}
{{ make_tab_item('admin', 'fa fa-edit', url('admin:judge_organization_change', organization.id), _('Admin')) }}
{% endif %}
</div>

View file

@ -0,0 +1,4 @@
{% extends "problem/list.html" %}
{% block left_sidebar %}
{% include "organization/org-left-sidebar.html" %}
{% endblock %}

View file

@ -1,4 +1,4 @@
{% extends "user/base-users.html" %}
{% extends "user/base-users-three-col.html" %}
{% block users_media %}
<style>
.kick-form .button {
@ -36,4 +36,8 @@
</script>
{% endblock %}
{% block left_sidebar %}
{% include "organization/org-left-sidebar.html" %}
{% endblock %}
{% block users_table %}{% include "organization/users-table.html" %}{% endblock %}

View file

@ -1,4 +1,24 @@
<div class="blog-box">
{% extends "problem/list-base.html" %}
{% block left_sidebar %}
{% include "problem/left-sidebar.html" %}
{% endblock %}
{% block middle_content %}
<div class="problem-feed-option">
<a href="{{url('problem_feed')}}" class="problem-feed-option-item {{'active' if feed_type=='for_you'}}">
{{_('FOR YOU')}}
</a>
<a href="{{url('problem_feed_new')}}" class="problem-feed-option-item {{'active' if feed_type=='new'}}">
{{_('NEW')}}
</a>
{% if request.user.has_perm('judge.suggest_problem_changes') %}
<a href="{{url('problem_feed_volunteer')}}" class="problem-feed-option-item {{'active' if feed_type=='volunteer'}}">
{{_('VOLUNTEER')}}
</a>
{% endif %}
</div>
{% for problem in problems %}
<div class="blog-box">
<h3 class="problem-feed-name">
<a href="{{ url('problem_detail', problem.code) }}">
{{ problem.name }}
@ -93,5 +113,9 @@
<center id="thank-{{problem.id}}" style="display: none; margin-top: 3em"></center>
{% endif %}
</div>
</div>
</div>
{% endfor %}
{% if page_obj.num_pages > 1 %}
<div style="margin-top:10px;">{% include "list-pages.html" %}</div>
{% endif %}
{% endblock %}

View file

@ -0,0 +1,7 @@
{% if not request.in_contest_mode %}
<div class="left-sidebar">
{{ make_tab_item('feed', 'fa fa-pagelines', url('problem_feed'), _('Feed')) }}
{{ make_tab_item('list', 'fa fa-list', url('problem_list'), _('List')) }}
{{ make_tab_item('admin', 'fa fa-edit', url('admin:judge_problem_changelist'), _('Admin')) }}
</div>
{% endif %}

View file

@ -0,0 +1,450 @@
{% extends "three-column-content.html" %}
{% block three_col_media %}
<link rel="stylesheet" href="{{ static('libs/nouislider.min.css') }}">
<noscript>
<style>
#category, #types {
visibility: visible;
}
</style>
</noscript>
{% if not request.in_contest_mode %}
<style>
#search-org, #search-author {
width: 100%;
}
#problem-table th {
padding: 0;
}
a.hot-problem-link:hover > .hot-problem-count {
visibility: visible;
}
span.hot-problem-count {
color: #555;
font-size: 0.75em;
vertical-align: super;
visibility: hidden;
padding-left: 0.25em;
position: relative;
}
ul.problem-list {
padding: 0 !important;
}
#content {
width: 99%;
margin-left: 0;
}
.volunteer-types {
width: 100%;
}
.point-input {
height: 2em;
padding-top: 4px;
}
</style>
{% endif %}
{% endblock %}
{% block three_col_js %}
<script>
window.point_start = {{point_start}};
window.point_end = {{point_end}};
window.point_values = {{point_values|json|safe}};
</script>
{% compress js %}
<script src="{{ static('libs/nouislider.min.js') }}" type="text/javascript"></script>
<script>
$(function () {
{% if not request.in_contest_mode %}
// wrap middle and write column
if (window.matchMedia('(max-width: 799px)').matches) {
$('.middle-content').next().addBack().wrapAll('<div class="problem-middle-right"/>');
}
{% endif %}
var $form = $('form#filter-form');
var $search = $('#search');
var $category = $('#category');
function prep_form() {
$search.prop('disabled', !$search.val());
$category.prop('disabled', !$category.val());
}
function clear_point_interval() {
if ($('#search').val() !== "{{ search_query or '' }}") {
$('#point-start').remove();
$('#point-end').remove();
}
}
function clean_submit() {
prep_form();
clear_point_interval();
$form.submit();
}
function form_serialize() {
clear_point_interval();
return $form.serialize();
}
$category.select2().css({'visibility': 'visible'}).change(clean_submit);
$('#types').select2({multiple: 1, placeholder: '{{ _('Filter by type...') }}'})
.css({'visibility': 'visible'});
$('#search-org').select2({multiple: 1, placeholder: '{{ _('Organizations...') }}'})
.css({'visibility': 'visible'});
$('#search-author').select2({multiple: 1, placeholder: '{{ _('Authors') }}...'})
.css({'visibility': 'visible'});
// This is incredibly nasty to do but it's needed because otherwise the select2 steals the focus
$search.keypress(function (e) {
if (e.keyCode == 13)
$('#go').click();
});
$('#random').click(function (e) {
var action = $form.attr('action');
$form.attr('action', '{{ url('problem_random') }}').attr('target', '_blank').submit();
$form.attr('action', action).attr('target', '');
e.preventDefault();
});
$('#go').click(clean_submit);
$('input#full_text, input#hide_solved, input#show_types, input#show_editorial, input#have_editorial').click(function () {
prep_form();
($('<form>').attr('action', window.location.pathname + '?' + form_serialize())
.append($('<input>').attr('type', 'hidden').attr('name', 'csrfmiddlewaretoken')
.attr('value', $.cookie('csrftoken')))
.attr('method', 'POST').appendTo($('body')).submit());
});
var intFormatter = {
to: function (value) {
return value;
},
from: function (value) {
return +value;
}
};
var $slider = $('#point-slider');
if ($slider.length) {
var $start = $('#point-start');
var $end = $('#point-end');
noUiSlider.create($slider[0], {
start: [point_start, point_end],
connect: true,
snap: true,
tooltips: [intFormatter, intFormatter],
range: point_values
}).on('change', function (values) {
var start = +values[0], end = +values[1];
$start.prop('disabled', start === point_values.min).val(start);
$end.prop('disabled', end === point_values.max).val(end);
});
}
{% if feed_type=='volunteer' and request.user.has_perm('judge.suggest_problem_changes') %}
$(".edit-btn").on('click', function() {
var pid = $(this).attr('pid');
$('#volunteer-types-' + pid).css({'width': '100%'});
$('#volunteer-types-' + pid).select2({multiple: 1, placeholder: '{{ _('Add types...') }}'})
.css({'visibility': 'visible'});
$('#form-' + pid).show();
$('#submit-' + pid).show();
$(this).hide();
});
let isChecking = false;
$(".volunteer-submit-btn").on('click', function(e) {
var pid = $(this).attr('pid');
var pcode = $(this).attr('pcode');
var $form = $('#form-' + pid);
if (!$form[0].checkValidity()) {
if (isChecking) return;
isChecking = true;
// The form won't actually submit;
$(this).click();
}
else {
isChecking = false;
}
if (isChecking) return;
e.preventDefault();
$('#volunteer-types-' + pid).select2({multiple: 1, placeholder: '{{ _('Add types...') }}'})
.css({'visibility': 'visible'});
$('#form-' + pid).hide();
$('#edit-' + pid).show();
$('#thank-' + pid).show();
$(this).hide();
var data = {
problem: pcode,
types: $('#volunteer-types-' + pid).val(),
knowledge_points: $('#knowledge_point-' + pid).val(),
thinking_points: $('#thinking_point-' + pid).val(),
feedback: $('#feedback-' + pid).val(),
};
$.post("{{url('volunteer_problem_vote')}}", data)
.fail(function() {
$('#thank-' + pid).html("{{_('Fail to vote!')}}");
})
.done(function() {
$('#thank-' + pid).html("{{_('Successful vote! Thank you!')}}");
});
});
{% endif %}
});
</script>
{% endcompress %}
{% if request.in_contest_mode %}
{% compress js %}
<script src="{{ static('libs/tablesorter.js') }}" type="text/javascript"></script>
<script type="text/javascript">
$(function () {
$.tablesorter.addParser({
id: 'solvedsort',
is: function (s) {
return false;
},
format: function (s, table, cell, cellIndex) {
return $(cell).attr('solved');
},
type: 'numeric'
});
$('#problem-table').tablesorter({
headers: {
0: {
sorter: 'solvedsort'
}
},
textExtraction: function (node) {
node = $(node);
var text = node.text().replace(/^\s+|\s+$/g, '');
return (node.hasClass('p') ? text.replace(/p$/, '') : text);
}
});
window.register_contest_notification("{{url('contest_clarification_ajax', request.participation.contest.key)}}");
{% if request.in_contest_mode %}
$('.left-sidebar').hide();
$('.middle-content').css('max-width', '80%');
{% endif %}
});
</script>
{% endcompress %}
{% endif %}
{% endblock %}
{% block left_sidebar %}
{% if not request.in_contest_mode %}
<div class="left-sidebar">
{{ make_tab_item('feed', 'fa fa-pagelines', url('problem_feed'), _('Feed')) }}
{{ make_tab_item('list', 'fa fa-list', url('problem_list'), _('List')) }}
{{ make_tab_item('admin', 'fa fa-edit', url('admin:judge_problem_changelist'), _('Admin')) }}
</div>
{% endif %}
{% endblock %}
{% block middle_content %}
{% if in_contest_mode or page_type == 'list' %}
<div id="content-left" class="problems">
<table id="problem-table" class="table striped">
<thead>
<tr>
{% if request.in_contest_mode %}
{% if request.user.is_authenticated %}
<th class="solved"><i class="fa fa-check"></i></th>
{% endif %}
<th class="problem">{{ _('Problem') }}</th>
<th class="pcode">{{ _('Problem code') }}</th>
{% if show_types %}
<th>{{ _('Types') }}</th>
{% endif %}
<th class="points">{{ _('Points') }}</th>
<th class="users">{{ _('Users') }}</th>
{% else %}
{% if request.user.is_authenticated %}
<th class="solved">
<a href="{{ sort_links.solved }}"><i class="fa fa-check"></i>{{ sort_order.solved }}
</a>
</th>
{% endif %}
<th class="problem">
<a href="{{ sort_links.name }}">{{ _('Problem') }}{{ sort_order.name }}</a>
</th>
<th class="pcode">
<a href="{{ sort_links.code }}">{{ _('Problem code') }}</a>
</th>
<th class="category">
<a href="{{ sort_links.group }}">{{ _('Category') }}{{ sort_order.group }}</a>
</th>
{% if show_types %}
<th>
<a href="{{ sort_links.type }}">{{ _('Types') }}{{ sort_order.type }}</a>
</th>
{% endif %}
<th class="points">
<a href="{{ sort_links.points }}">{{ _('Points') }}{{ sort_order.points }}</a>
</th>
<th class="ac-rate">
<a href="{{ sort_links.ac_rate }}">{{ _('AC %%') }}{{ sort_order.ac_rate }}</a>
</th>
<th class="users">
<a href="{{ sort_links.user_count }}">{{ _('Users') }}{{ sort_order.user_count }}</a>
</th>
{% if show_editorial %}
<th class="editorial">
{{_('Editorial')}}
</th>
{% endif %}
{% endif %}
</tr>
</thead>
<tbody>
{% for problem in object_list %}
<tr>
{% if request.user.is_authenticated %}
{% if problem.id in completed_problem_ids %}
<td solved="1">
<a href="{{ url('user_submissions', problem.code, request.user.username) }}">
{% if problem.is_public or request.in_contest_mode %}
<i class="solved-problem-color fa fa-check-circle"></i>
{% else %}
<i class="solved-problem-color fa fa-lock"></i>
{% endif %}
</a>
</td>
{% elif problem.id in attempted_problems %}
<td solved="0">
<a href="{{ url('user_submissions', problem.code, request.user.username) }}">
{% if problem.is_public or request.in_contest_mode %}
<i class="attempted-problem-color fa fa-minus-circle"></i>
{% else %}
<i class="attempted-problem-color fa fa-lock"></i>
{% endif %}
</a>
</td>
{% else %}
<td solved="-1">
{% if problem.is_public or request.in_contest_mode %}
<i class="unsolved-problem-color fa fa-minus-circle"></i>
{% else %}
<i class="unsolved-problem-color fa fa-lock"></i>
{% endif %}
</td>
{% endif %}
{% endif %}
<td class="problem">
<a href="{{ url('problem_detail', problem.code) }}">{{ problem.i18n_name }}</a>
</td>
<td class="pcode">
<a class="pcodecell" href="{{ url('problem_detail', problem.code) }}">{{ problem.code }}</a>
</td>
{% if not request.in_contest_mode %}
<td class="category">{{ problem.group.full_name }}</td>
{% endif %}
{% if show_types %}
<td class="types">
{% for type in problem.types_list %}
<span class="type-tag">{{ type }}</span>{% if not loop.last %}, {% endif %}
{% endfor %}
</td>
{% endif %}
<td class="p">{{ problem.points|floatformat }}{% if problem.partial %}p{% endif %}</td>
{% if not request.in_contest_mode %}
<td class="ac-rate">{{ problem.ac_rate|floatformat(1) }}%</td>
{% endif %}
<td class="users">
<a href="{{ url('ranked_submissions', problem.code) }}">
{% if not request.in_contest_mode or not hide_contest_scoreboard %}
{{ problem.user_count }}
{% else %}
???
{% endif %}
</a>
</td>
{% if show_editorial%}
<td class="editorial">
{% if problem.has_public_editorial %}
<a href="{{ url('problem_editorial', problem.code) }}">{{ _('Editorial') }}</a>
{% endif %}
</td>
{% endif %}
</tr>
{% endfor %}
</tbody>
</table>
{% if request.in_contest_mode and request.participation.contest.use_clarifications %}
<br><br>
{% if can_edit_contest %}
<div style="float: right; font-size: 1.2em">
<a href="{{url('new_contest_clarification', request.participation.contest.key)}}"><i class="fa fa-plus-circle" style="color:green"></i> <u>{{_('Add clarifications')}}</u></a>
</div>
{% endif %}
{% if has_clarifications %}
<div style="font-size: 1.2em; font-style: bold">
<i class="fa fa-question-circle"></i> {{_('Clarifications')}}</div>
<table class="table">
<tr>
<th>{{_('Problem')}}</th>
<th>{{_('Time')}}</th>
<th>{{_('Description')}}</th>
</tr>
{% for clarification in clarifications %}
<tr>
<td>
<a href="{{ url('problem_detail', clarification.problem.code) }}"
class="problem">
{{ clarification.problem.name }}
</a>
</td>
<td class="time">{{ relative_time(clarification.date) }}</td>
<td><p style="overflow-wrap: break-word; word-break: break-word">{{clarification.description}}</p></td>
</tr>
{% endfor %}
</table>
{% else %}
<p style="font-style: italic; text-align: center">
{{ _('No clarifications have been made at this time.') }}</center>
</p>
{% endif %}
{% endif %}
</div>
{% elif page_type == 'feed' %}
<div class="problem-feed-option">
<a href="{{url('problem_feed')}}" class="problem-feed-option-item {{'active' if feed_type=='for_you'}}">
{{_('FOR YOU')}}
</a>
<a href="{{url('problem_feed_new')}}" class="problem-feed-option-item {{'active' if feed_type=='new'}}">
{{_('NEW')}}
</a>
{% if request.user.has_perm('judge.suggest_problem_changes') %}
<a href="{{url('problem_feed_volunteer')}}" class="problem-feed-option-item {{'active' if feed_type=='volunteer'}}">
{{_('VOLUNTEER')}}
</a>
{% endif %}
</div>
{% for problem in problems %}
{% include "problem/feed.html" %}
{% endfor %}
{% endif %}
{% if page_obj.num_pages > 1 %}
<div style="margin-top:10px;">{% include "list-pages.html" %}</div>
{% endif %}
{% endblock %}
{% block right_sidebar %}
{% if not request.in_contest_mode %}
<div id="content-right" class="problems right-sidebar">
{% include "problem/search-form.html" %}
{% include "problem/recent-attempt.html" %}
</div>
{% endif %}
{% endblock %}

View file

@ -1,258 +1,9 @@
{% extends "three-column-content.html" %}
{% block three_col_media %}
<link rel="stylesheet" href="{{ static('libs/nouislider.min.css') }}">
<noscript>
<style>
#category, #types {
visibility: visible;
}
</style>
</noscript>
{% if not request.in_contest_mode %}
<style>
#search-org, #search-author {
width: 100%;
}
#problem-table th {
padding: 0;
}
a.hot-problem-link:hover > .hot-problem-count {
visibility: visible;
}
span.hot-problem-count {
color: #555;
font-size: 0.75em;
vertical-align: super;
visibility: hidden;
padding-left: 0.25em;
position: relative;
}
ul.problem-list {
padding: 0 !important;
}
#content {
width: 99%;
margin-left: 0;
}
.volunteer-types {
width: 100%;
}
.point-input {
height: 2em;
padding-top: 4px;
}
</style>
{% endif %}
{% endblock %}
{% block three_col_js %}
<script>
window.point_start = {{point_start}};
window.point_end = {{point_end}};
window.point_values = {{point_values|json|safe}};
</script>
{% compress js %}
<script src="{{ static('libs/nouislider.min.js') }}" type="text/javascript"></script>
<script>
$(function () {
{% if not request.in_contest_mode %}
// wrap middle and write column
if (window.matchMedia('(max-width: 799px)').matches) {
$('.middle-content').next().addBack().wrapAll('<div class="problem-middle-right"/>');
}
{% endif %}
var $form = $('form#filter-form');
var $search = $('#search');
var $category = $('#category');
function prep_form() {
$search.prop('disabled', !$search.val());
$category.prop('disabled', !$category.val());
}
function clear_point_interval() {
if ($('#search').val() !== "{{ search_query or '' }}") {
$('#point-start').remove();
$('#point-end').remove();
}
}
function clean_submit() {
prep_form();
clear_point_interval();
$form.submit();
}
function form_serialize() {
clear_point_interval();
return $form.serialize();
}
$category.select2().css({'visibility': 'visible'}).change(clean_submit);
$('#types').select2({multiple: 1, placeholder: '{{ _('Filter by type...') }}'})
.css({'visibility': 'visible'});
$('#search-org').select2({multiple: 1, placeholder: '{{ _('Organizations...') }}'})
.css({'visibility': 'visible'});
$('#search-author').select2({multiple: 1, placeholder: '{{ _('Authors') }}...'})
.css({'visibility': 'visible'});
// This is incredibly nasty to do but it's needed because otherwise the select2 steals the focus
$search.keypress(function (e) {
if (e.keyCode == 13)
$('#go').click();
});
$('#random').click(function (e) {
var action = $form.attr('action');
$form.attr('action', '{{ url('problem_random') }}').attr('target', '_blank').submit();
$form.attr('action', action).attr('target', '');
e.preventDefault();
});
$('#go').click(clean_submit);
$('input#full_text, input#hide_solved, input#show_types, input#show_editorial, input#have_editorial').click(function () {
prep_form();
($('<form>').attr('action', window.location.pathname + '?' + form_serialize())
.append($('<input>').attr('type', 'hidden').attr('name', 'csrfmiddlewaretoken')
.attr('value', $.cookie('csrftoken')))
.attr('method', 'POST').appendTo($('body')).submit());
});
var intFormatter = {
to: function (value) {
return value;
},
from: function (value) {
return +value;
}
};
var $slider = $('#point-slider');
if ($slider.length) {
var $start = $('#point-start');
var $end = $('#point-end');
noUiSlider.create($slider[0], {
start: [point_start, point_end],
connect: true,
snap: true,
tooltips: [intFormatter, intFormatter],
range: point_values
}).on('change', function (values) {
var start = +values[0], end = +values[1];
$start.prop('disabled', start === point_values.min).val(start);
$end.prop('disabled', end === point_values.max).val(end);
});
}
{% if feed_type=='volunteer' and request.user.has_perm('judge.suggest_problem_changes') %}
$(".edit-btn").on('click', function() {
var pid = $(this).attr('pid');
$('#volunteer-types-' + pid).css({'width': '100%'});
$('#volunteer-types-' + pid).select2({multiple: 1, placeholder: '{{ _('Add types...') }}'})
.css({'visibility': 'visible'});
$('#form-' + pid).show();
$('#submit-' + pid).show();
$(this).hide();
});
let isChecking = false;
$(".volunteer-submit-btn").on('click', function(e) {
var pid = $(this).attr('pid');
var pcode = $(this).attr('pcode');
var $form = $('#form-' + pid);
if (!$form[0].checkValidity()) {
if (isChecking) return;
isChecking = true;
// The form won't actually submit;
$(this).click();
}
else {
isChecking = false;
}
if (isChecking) return;
e.preventDefault();
$('#volunteer-types-' + pid).select2({multiple: 1, placeholder: '{{ _('Add types...') }}'})
.css({'visibility': 'visible'});
$('#form-' + pid).hide();
$('#edit-' + pid).show();
$('#thank-' + pid).show();
$(this).hide();
var data = {
problem: pcode,
types: $('#volunteer-types-' + pid).val(),
knowledge_points: $('#knowledge_point-' + pid).val(),
thinking_points: $('#thinking_point-' + pid).val(),
feedback: $('#feedback-' + pid).val(),
};
$.post("{{url('volunteer_problem_vote')}}", data)
.fail(function() {
$('#thank-' + pid).html("{{_('Fail to vote!')}}");
})
.done(function() {
$('#thank-' + pid).html("{{_('Successful vote! Thank you!')}}");
});
});
{% endif %}
});
</script>
{% endcompress %}
{% if request.in_contest_mode %}
{% compress js %}
<script src="{{ static('libs/tablesorter.js') }}" type="text/javascript"></script>
<script type="text/javascript">
$(function () {
$.tablesorter.addParser({
id: 'solvedsort',
is: function (s) {
return false;
},
format: function (s, table, cell, cellIndex) {
return $(cell).attr('solved');
},
type: 'numeric'
});
$('#problem-table').tablesorter({
headers: {
0: {
sorter: 'solvedsort'
}
},
textExtraction: function (node) {
node = $(node);
var text = node.text().replace(/^\s+|\s+$/g, '');
return (node.hasClass('p') ? text.replace(/p$/, '') : text);
}
});
window.register_contest_notification("{{url('contest_clarification_ajax', request.participation.contest.key)}}");
{% if request.in_contest_mode %}
$('.left-sidebar').hide();
$('.middle-content').css('max-width', '80%');
{% endif %}
});
</script>
{% endcompress %}
{% endif %}
{% endblock %}
{% extends "problem/list-base.html" %}
{% block left_sidebar %}
{% if not request.in_contest_mode %}
<div class="left-sidebar">
{{ make_tab_item('feed', 'fa fa-pagelines', url('problem_feed'), _('Feed')) }}
{{ make_tab_item('list', 'fa fa-list', url('problem_list'), _('List')) }}
{{ make_tab_item('admin', 'fa fa-edit', url('admin:judge_problem_changelist'), _('Admin')) }}
</div>
{% endif %}
{% include "problem/left-sidebar.html" %}
{% endblock %}
{% block middle_content %}
{% if in_contest_mode or page_type == 'list' %}
<div id="content-left" class="problems">
<table id="problem-table" class="table striped">
<thead>
@ -415,36 +166,8 @@
</p>
{% endif %}
{% endif %}
</div>
{% elif page_type == 'feed' %}
<div class="problem-feed-option">
<a href="{{url('problem_feed')}}" class="problem-feed-option-item {{'active' if feed_type=='for_you'}}">
{{_('FOR YOU')}}
</a>
<a href="{{url('problem_feed_new')}}" class="problem-feed-option-item {{'active' if feed_type=='new'}}">
{{_('NEW')}}
</a>
{% if request.user.has_perm('judge.suggest_problem_changes') %}
<a href="{{url('problem_feed_volunteer')}}" class="problem-feed-option-item {{'active' if feed_type=='volunteer'}}">
{{_('VOLUNTEER')}}
</a>
{% endif %}
</div>
{% for problem in problems %}
{% include "problem/feed.html" %}
{% endfor %}
{% endif %}
{% if page_obj.num_pages > 1 %}
<div style="margin-top:10px;">{% include "list-pages.html" %}</div>
{% endif %}
{% endblock %}
{% block right_sidebar %}
{% if not request.in_contest_mode %}
<div id="content-right" class="problems right-sidebar">
{% include "problem/search-form.html" %}
{% include "problem/recent-attempt.html" %}
</div>
{% endif %}
{% endblock %}

View file

@ -19,19 +19,21 @@
{% if show_types %} checked{% endif %}>
<label for="show_types">{{ _('Show problem types') }}</label>
</div>
{% if page_type == 'list' %}
{% if has_show_editorial_option %}
<div>
<input id="show_editorial" type="checkbox" name="show_editorial" value="1"
{% if show_editorial %} checked{% endif %}>
<label for="show_editorial">{{ _('Show editorial') }}</label>
</div>
{% elif page_type == 'feed' %}
{% endif %}
{% if has_have_editorial_option %}
<div>
<input id="have_editorial" type="checkbox" name="have_editorial" value="1"
{% if have_editorial %} checked{% endif %}>
<label for="have_editorial">{{ _('Have editorial') }}</label>
</div>
{% endif %}
{% if organizations %}
<div class="filter-form-group">
<label for="type"><i>{{ _('Organization') }}</i></label>
<select id="search-org" name="orgs" multiple>
@ -42,6 +44,7 @@
{% endfor %}
</select>
</div>
{% endif %}
<div class="filter-form-group">
<label for="type"><i>{{ _('Author') }}</i></label>
<select id="search-author" name="authors" multiple>
@ -66,7 +69,6 @@
</option>
{% endfor %}
</select>
</div>
{% if show_types %}
<div class="filter-form-group">

37
templates/top-users.html Normal file
View file

@ -0,0 +1,37 @@
{% if top_rated %}
<div class="blog-sidebox sidebox">
<h3>{{ _('Top Rating') }} <i class="fa fa-trophy"></i></h3>
<div class="sidebox-content" style="padding: 0; border: 0">
<table class="table feed-table">
<tbody>
{% for user in top_rated %}
<tr>
<td style="padding: 7px 2px"><b>{{loop.index}}</b></td>
<td>{{link_user(user)}}</td>
<td>{{user.rating}}</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
{% endif %}
{% if top_scorer %}
<div class="blog-sidebox sidebox">
<h3>{{ _('Top Score') }} <i class="fa fa-trophy"></i></h3>
<div class="sidebox-content" style="padding: 0; border: 0">
<table class="table feed-table">
<tbody>
{% for user in top_scorer %}
<tr>
<td style="padding: 7px 2px"><b>{{loop.index}}</b></td>
<td>{{link_user(user)}}</td>
<td>{{ user.performance_points|floatformat(0) }}</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
{% endif %}

View file

@ -0,0 +1,102 @@
{% extends "three-column-content.html" %}
{% block three_col_js %}
{% block users_js_media %}{% endblock %}
<script>
$(function () {
$('#search-handle').replaceWith($('<select>').attr({
id: 'search-handle',
name: 'handle',
onchange: 'form.submit()'
}));
var in_user_redirect = false;
$('#search-handle').select2({
placeholder: '{{ _('Search by handle...') }}',
ajax: {
url: '{{ url('user_search_select2_ajax') }}'
},
minimumInputLength: 1,
escapeMarkup: function (markup) {
return markup;
},
templateResult: function (data, container) {
return $('<span>')
.append($('<img>', {
'class': 'user-search-image', src: data.gravatar_url,
width: 24, height: 24
}))
.append($('<span>', {'class': data.display_rank + ' user-search-name'}).text(data.text))
.append($('<a>', {href: '/user/' + data.text, 'class': 'user-redirect'})
.append($('<i>', {'class': 'fa fa-mail-forward'}))
.mouseover(function () {
in_user_redirect = true;
}).mouseout(function () {
in_user_redirect = false;
}));
}
}).on('select2:selecting', function () {
return !in_user_redirect;
});
var $last = null;
$(window).on('hashchange', function () {
var hash = window.location.hash;
if (hash.startsWith('#!')) {
var $user = $('#user-' + hash.substring(2)).addClass('highlight');
if ($user) {
$(document).scrollTop($user.position().top - 50);
if ($last !== null) $last.removeClass('highlight');
$last = $user;
}
}
}).trigger('hashchange');
$('.about-td').on('click', function() {
var max_height = $(this).css('max-height');
if (max_height !== 'fit-content') {
$(this).css('max-height', 'fit-content');
}
else {
$(this).css('max-height', '45px');
}
})
});
</script>
{% endblock %}
{% block three_col_media %}
<link href="http://fonts.cdnfonts.com/css/jersey-m54" rel="stylesheet">
<style>
@media (min-width: 800px) {
.middle-content {
max-width: none;
padding-left: 1em;
}
}
</style>
{% block users_media %}{% endblock %}
{% endblock %}
{% block middle_content %}
<div id="common-content">
<div id="content-left" class="users">
{% if page_obj and page_obj.num_pages > 1 %}
<div style="margin-bottom: 7px; margin-top: 3px;">
{% include "list-pages.html" %}
<form id="search-form" name="form" action="{{ url('user_ranking_redirect') }}" method="get">
<input id="search-handle" type="text" name="search"
placeholder="{{ _('Search by handle...') }}">
</form>
</div>
{% endif %}
<table id="users-table" class="table">
{% block users_table %}{% endblock %}
</table>
{% if page_obj and page_obj.num_pages > 1 %}
<div style="margin-top:10px;">{% include "list-pages.html" %}</div>
{% endif %}
</div>
</div>
{% endblock %}