Merge pull request #16 from LQDJudge/master

Merge from master
This commit is contained in:
Phuoc Dinh Le 2022-02-26 20:11:42 -06:00 committed by GitHub
commit 127284e812
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
24 changed files with 303 additions and 145 deletions

View file

@ -375,9 +375,10 @@ def get_or_create_room(request):
# TODO: each user can only create <= 300 rooms
room = get_room(other_user, user)
for u in [other_user, user]:
user_room, _ = UserRoom.objects.get_or_create(user=u, room=room)
user_room.last_seen = timezone.now()
user_room.save()
user_room, created = UserRoom.objects.get_or_create(user=u, room=room)
if created:
user_room.last_seen = timezone.now()
user_room.save()
if request.method == 'GET':
return JsonResponse({'room': room.id, 'other_user_id': other_user.id})

View file

@ -1,4 +1,4 @@
from chat_box.views import *
import chat_box.views as chat
from django.conf import settings
from django.conf.urls import include, url
@ -280,6 +280,7 @@ urlpatterns = [
url(r'^mailgun/mail_activate/$', mailgun.MailgunActivationView.as_view(), name='mailgun_activate'),
url(r'^widgets/', include([
url(r'^contest_mode$', contests.update_contest_mode, name='contest_mode_ajax'),
url(r'^rejudge$', widgets.rejudge_submission, name='submission_rejudge'),
url(r'^single_submission$', submission.single_submission_query, name='submission_single_query'),
url(r'^submission_testcases$', submission.SubmissionTestCaseQuery.as_view(), name='submission_testcases_query'),
@ -376,16 +377,16 @@ urlpatterns = [
url(r'^custom_checker_sample/', about.custom_checker_sample, name='custom_checker_sample'),
url(r'^chat/', include([
url(r'^(?P<room_id>\d*)$', login_required(ChatView.as_view()), name='chat'),
url(r'^delete/$', delete_message, name='delete_chat_message'),
url(r'^post/$', post_message, name='post_chat_message'),
url(r'^ajax$', chat_message_ajax, name='chat_message_ajax'),
url(r'^online_status/ajax$', online_status_ajax, name='online_status_ajax'),
url(r'^get_or_create_room$', get_or_create_room, name='get_or_create_room'),
url(r'^update_last_seen$', update_last_seen, name='update_last_seen'),
url(r'^online_status/user/ajax$', user_online_status_ajax, name='user_online_status_ajax'),
url(r'^toggle_ignore/(?P<user_id>\d+)$', toggle_ignore, name='toggle_ignore'),
url(r'^get_unread_boxes$', get_unread_boxes, name='get_unread_boxes'),
url(r'^(?P<room_id>\d*)$', login_required(chat.ChatView.as_view()), name='chat'),
url(r'^delete/$', chat.delete_message, name='delete_chat_message'),
url(r'^post/$', chat.post_message, name='post_chat_message'),
url(r'^ajax$', chat.chat_message_ajax, name='chat_message_ajax'),
url(r'^online_status/ajax$', chat.online_status_ajax, name='online_status_ajax'),
url(r'^get_or_create_room$', chat.get_or_create_room, name='get_or_create_room'),
url(r'^update_last_seen$', chat.update_last_seen, name='update_last_seen'),
url(r'^online_status/user/ajax$', chat.user_online_status_ajax, name='user_online_status_ajax'),
url(r'^toggle_ignore/(?P<user_id>\d+)$', chat.toggle_ignore, name='toggle_ignore'),
url(r'^get_unread_boxes$', chat.get_unread_boxes, name='get_unread_boxes'),
])),
url(r'^notifications/',

View file

@ -57,7 +57,9 @@ class ContestMiddleware(object):
profile.update_contest()
request.participation = profile.current_contest
request.in_contest = request.participation is not None
request.contest_mode = request.session.get('contest_mode', True)
else:
request.in_contest = False
request.participation = None
request.in_contest_mode = request.in_contest and request.contest_mode
return self.get_response(request)

View file

@ -286,7 +286,11 @@ def get_problem_case(problem, files):
s.decode('utf-8')
break
except UnicodeDecodeError:
s += f.read(1)
next_char = f.read(1)
if next_char:
s += next_char
else:
raise Exception('File %s is not able to decode in utf-8' % file)
qs = get_visible_content(s)
cache.set(cache_key, qs, 86400)
result[file] = qs

View file

@ -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, JsonResponse
from django.http import Http404, HttpResponse, HttpResponseBadRequest, HttpResponseRedirect, JsonResponse, HttpResponseNotAllowed
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
@ -46,7 +46,7 @@ from judge.widgets import HeavyPreviewPageDownWidget
__all__ = ['ContestList', 'ContestDetail', 'ContestRanking', 'ContestJoin', 'ContestLeave', 'ContestCalendar',
'ContestClone', 'ContestStats', 'ContestMossView', 'ContestMossDelete', 'contest_ranking_ajax',
'ContestParticipationList', 'ContestParticipationDisqualify', 'get_contest_ranking_list',
'base_contest_ranking_list', 'ContestClarificationView']
'base_contest_ranking_list', 'ContestClarificationView', 'update_contest_mode']
def _find_contest(request, key, private_check=True):
@ -428,6 +428,7 @@ class ContestLeave(LoginRequiredMixin, ContestMixin, BaseDetailView):
_('You are not in contest "%s".') % contest.key, 404)
profile.remove_contest()
request.session['contest_mode'] = True # reset contest_mode
return HttpResponseRedirect(reverse('contest_view', args=(contest.key,)))
@ -660,7 +661,7 @@ def get_contest_ranking_list(request, contest, participation=None, ranking_list=
problems = list(contest.contest_problems.select_related('problem').defer('problem__description').order_by('order'))
users = ranker(ranking_list(contest, problems), key=attrgetter('points', 'cumtime', 'tiebreaker'))
if show_current_virtual:
if participation is None and request.user.is_authenticated:
participation = request.profile.current_contest
@ -953,3 +954,12 @@ class ContestClarificationAjax(ContestMixin, DetailView):
cla['order'] = self.object.get_label_for_problem(problems.index(cla['problem']))
return JsonResponse(queryset, safe=False, json_dumps_params={'ensure_ascii': False})
def update_contest_mode(request):
if not request.is_ajax() or not request.method=='POST':
return HttpResponseNotAllowed(['POST'])
old_mode = request.session.get('contest_mode', True)
request.session['contest_mode'] = not old_mode
return HttpResponse()

View file

@ -71,7 +71,8 @@ class ProblemMixin(object):
def get(self, request, *args, **kwargs):
try:
return super(ProblemMixin, self).get(request, *args, **kwargs)
except Http404:
except Http404 as e:
print(e)
return self.no_such_problem()
@ -90,7 +91,8 @@ class SolvedProblemMixin(object):
@cached_property
def in_contest(self):
return self.profile is not None and self.profile.current_contest is not None
return self.profile is not None and self.profile.current_contest is not None \
and self.request.in_contest_mode
@cached_property
def contest(self):
@ -120,10 +122,9 @@ class ProblemSolution(SolvedProblemMixin, ProblemMixin, TitleMixin, CommentedDet
solution = get_object_or_404(Solution, problem=self.object)
if (not solution.is_public or solution.publish_on > timezone.now()) and \
not self.request.user.has_perm('judge.see_private_solution') or \
(self.request.user.is_authenticated and
self.request.profile.current_contest):
not self.request.user.has_perm('judge.see_private_solution'):
raise Http404()
context['solution'] = solution
context['has_solved_problem'] = self.object.id in self.get_completed_problems()
return context

View file

@ -249,7 +249,7 @@ def problem_init_view(request, problem):
raise Http404()
return render(request, 'problem/yaml.html', {
'raw_source': data, 'highlighted_source': highlight_code(data, 'yaml'),
'raw_source': data, 'highlighted_source': highlight_code(data, 'yaml', linenos=False),
'title': _('Generated init.yml for %s') % problem.name,
'content_title': mark_safe(escape(_('Generated init.yml for %s')) % (
format_html('<a href="{1}">{0}</a>', problem.name,

View file

@ -262,7 +262,8 @@ class SubmissionsListBase(DiggPaginatorMixin, TitleMixin, ListView):
@cached_property
def in_contest(self):
return self.request.user.is_authenticated and self.request.profile.current_contest is not None
return self.request.user.is_authenticated and self.request.profile.current_contest is not None \
and self.request.in_contest_mode
@cached_property
def contest(self):

View file

@ -92,7 +92,8 @@ class UserPage(TitleMixin, UserMixin, DetailView):
@cached_property
def in_contest(self):
return self.profile is not None and self.profile.current_contest is not None
return self.profile is not None and self.profile.current_contest is not None \
and self.request.in_contest_mode
def get_completed_problems(self):
if self.in_contest:
@ -374,8 +375,8 @@ class FixedContestRanking(ContestRanking):
def users(request):
if request.user.is_authenticated:
participation = request.profile.current_contest
if participation is not None:
if request.in_contest_mode:
participation = request.profile.current_contest
contest = participation.contest
return FixedContestRanking.as_view(contest=contest)(request, contest=contest.key)
return user_list_view(request)

View file

@ -2,7 +2,7 @@ msgid ""
msgstr ""
"Project-Id-Version: lqdoj2\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2021-12-29 13:13+0700\n"
"POT-Creation-Date: 2022-01-10 18:14+0700\n"
"PO-Revision-Date: 2021-07-20 03:44\n"
"Last-Translator: Icyene\n"
"Language-Team: Vietnamese\n"
@ -108,7 +108,7 @@ msgstr ""
msgid "Login"
msgstr "Đăng nhập"
#: dmoj/urls.py:106 templates/base.html:207
#: dmoj/urls.py:106 templates/base.html:249
msgid "Home"
msgstr "Trang chủ"
@ -217,7 +217,7 @@ msgstr "Tính toán lại kết quả"
msgid "username"
msgstr "tên đăng nhập"
#: judge/admin/contest.py:320 templates/base.html:294
#: judge/admin/contest.py:320 templates/base.html:337
msgid "virtual"
msgstr "ảo"
@ -318,7 +318,7 @@ msgstr "Email"
#: judge/admin/profile.py:96 judge/views/register.py:29
#: templates/registration/registration_form.html:173
#: templates/user/edit-profile.html:114
#: templates/user/edit-profile.html:116
msgid "Timezone"
msgstr "Múi giờ"
@ -2438,71 +2438,71 @@ msgstr "Nhập mật khẩu truy cập cho \"%s\""
msgid "You are not in contest \"%s\"."
msgstr "Bạn không ở trong kỳ thi \"%s\"."
#: judge/views/contests.py:447
#: judge/views/contests.py:448
msgid "ContestCalendar requires integer year and month"
msgstr "Lịch thi yêu cầu giá trị cho năm và tháng là số nguyên"
#: judge/views/contests.py:487
#: judge/views/contests.py:488
#, python-format
msgid "Contests in %(month)s"
msgstr "Các kỳ thi trong %(month)s"
#: judge/views/contests.py:487
#: judge/views/contests.py:488
msgid "F Y"
msgstr "F Y"
#: judge/views/contests.py:535
#: judge/views/contests.py:536
#, python-format
msgid "%s Statistics"
msgstr "%s Thống kê"
#: judge/views/contests.py:730
#: judge/views/contests.py:731
#, python-format
msgid "%s Rankings"
msgstr "%s Bảng điểm"
#: judge/views/contests.py:738
#: judge/views/contests.py:739
msgid "???"
msgstr "???"
#: judge/views/contests.py:754
#: judge/views/contests.py:755
#, python-format
msgid "Your participation in %s"
msgstr "Lần tham gia trong %s"
#: judge/views/contests.py:755
#: judge/views/contests.py:756
#, python-format
msgid "%s's participation in %s"
msgstr "Lần tham gia của %s trong %s"
#: judge/views/contests.py:762
#: judge/views/contests.py:763
msgid "Live"
msgstr "Trực tiếp"
#: judge/views/contests.py:774 templates/contest/contest-tabs.html:13
#: judge/views/contests.py:775 templates/contest/contest-tabs.html:13
msgid "Participation"
msgstr "Lần tham gia"
#: judge/views/contests.py:821
#: judge/views/contests.py:822
#, python-format
msgid "%s MOSS Results"
msgstr "%s Kết quả MOSS"
#: judge/views/contests.py:848
#: judge/views/contests.py:849
#, python-format
msgid "Running MOSS for %s..."
msgstr "Đang chạy MOSS cho %s..."
#: judge/views/contests.py:871
#: judge/views/contests.py:872
#, python-format
msgid "Contest tag: %s"
msgstr "Nhãn kỳ thi: %s"
#: judge/views/contests.py:881 judge/views/ticket.py:57
#: judge/views/contests.py:882 judge/views/ticket.py:57
msgid "Issue description"
msgstr "Mô tả vấn đề"
#: judge/views/contests.py:924
#: judge/views/contests.py:925
#, python-format
msgid "New clarification for %s"
msgstr "Thông báo mới cho %s"
@ -2656,56 +2656,56 @@ msgstr "Không có bài nào như vậy"
msgid "Could not find a problem with the code \"%s\"."
msgstr "Không tìm thấy bài tập với mã bài \"%s\"."
#: judge/views/problem.py:111
#: judge/views/problem.py:113
#, python-brace-format
msgid "Editorial for {0}"
msgstr "Hướng dẫn cho {0}"
#: judge/views/problem.py:114
#: judge/views/problem.py:116
#, python-brace-format
msgid "Editorial for <a href=\"{1}\">{0}</a>"
msgstr "Hướng dẫn cho <a href=\"{1}\">{0}</a>"
#: judge/views/problem.py:226
#: judge/views/problem.py:227
#, python-brace-format
msgid "Disscuss {0}"
msgstr ""
#: judge/views/problem.py:229
#: judge/views/problem.py:230
#, python-brace-format
msgid "Discuss <a href=\"{1}\">{0}</a>"
msgstr "Thảo luận <a href=\"{1}\">{0}</a>"
#: judge/views/problem.py:297 templates/contest/contest.html:79
#: judge/views/problem.py:298 templates/contest/contest.html:79
#: templates/user/user-about.html:28 templates/user/user-tabs.html:5
#: templates/user/users-table.html:29
msgid "Problems"
msgstr "Bài tập"
#: judge/views/problem.py:597
#: judge/views/problem.py:598
msgid "Banned from submitting"
msgstr "Bị cấm nộp bài"
#: judge/views/problem.py:598
#: judge/views/problem.py:599
msgid ""
"You have been declared persona non grata for this problem. You are "
"permanently barred from submitting this problem."
msgstr "Bạn đã bị cấm nộp bài này."
#: judge/views/problem.py:612
#: judge/views/problem.py:613
msgid "Too many submissions"
msgstr "Quá nhiều lần nộp"
#: judge/views/problem.py:613
#: judge/views/problem.py:614
msgid "You have exceeded the submission limit for this problem."
msgstr "Bạn đã vượt quá số lần nộp cho bài này."
#: judge/views/problem.py:673 judge/views/problem.py:676
#: judge/views/problem.py:674 judge/views/problem.py:677
#, python-format
msgid "Submit to %(problem)s"
msgstr "Nộp bài cho %(problem)s"
#: judge/views/problem.py:691
#: judge/views/problem.py:692
msgid "Clone Problem"
msgstr "Nhân bản bài tập"
@ -2803,7 +2803,7 @@ msgstr "Các bài nộp tốt nhất cho bài {0} trong <a href=\"{2}\">{1}</a>"
msgid "A username must contain letters, numbers, or underscores"
msgstr "Tên đăng nhập phải chứa ký tự, chữ số, hoặc dấu gạch dưới"
#: judge/views/register.py:31 templates/user/edit-profile.html:118
#: judge/views/register.py:31 templates/user/edit-profile.html:120
msgid "Preferred language"
msgstr "Ngôn ngữ ưa thích"
@ -2857,39 +2857,39 @@ msgstr "Bài nộp của %(user)s cho bài %(problem)s"
msgid "All submissions"
msgstr "Tất cả bài nộp"
#: judge/views/submission.py:404
#: judge/views/submission.py:405
msgid "All my submissions"
msgstr "Tất cả bài nộp của tôi"
#: judge/views/submission.py:405
#: judge/views/submission.py:406
#, python-format
msgid "All submissions by %s"
msgstr "Tất cả bài nộp của %s"
#: judge/views/submission.py:436
#: judge/views/submission.py:437
#, python-format
msgid "All submissions for %s"
msgstr "Tất cả bài nộp cho %s"
#: judge/views/submission.py:455
#: judge/views/submission.py:456
msgid "Must pass a problem"
msgstr "Phải làm được một bài"
#: judge/views/submission.py:501
#: judge/views/submission.py:502
#, python-format
msgid "My submissions for %(problem)s"
msgstr "Bài nộp của tôi cho %(problem)s"
#: judge/views/submission.py:502
#: judge/views/submission.py:503
#, python-format
msgid "%(user)s's submissions for %(problem)s"
msgstr "Các bài nộp của %(user)s cho %(problem)s"
#: judge/views/submission.py:603
#: judge/views/submission.py:604
msgid "Must pass a contest"
msgstr "Phải qua một kỳ thi"
#: judge/views/submission.py:622
#: judge/views/submission.py:623
#, python-brace-format
msgid ""
"<a href=\"{1}\">{0}</a>'s submissions for <a href=\"{3}\">{2}</a> in <a href="
@ -2898,7 +2898,7 @@ msgstr ""
"Các bài nộp của <a href=\"{1}\">{0}</a> cho <a href=\"{3}\">{2}</a> trong <a "
"href=\"{5}\">{4}</a>"
#: judge/views/submission.py:629
#: judge/views/submission.py:630
#, python-brace-format
msgid ""
"<a href=\"{1}\">{0}</a>'s submissions for problem {2} in <a href=\"{4}\">{3}"
@ -2979,29 +2979,29 @@ msgstr "Tài khoản của tôi"
msgid "User %s"
msgstr "Thành viên %s"
#: judge/views/user.py:148
#: judge/views/user.py:149
msgid "M j, Y"
msgstr "j M, Y"
#: judge/views/user.py:171
#: judge/views/user.py:172
msgid "M j, Y, G:i"
msgstr "j M, Y, G:i"
#: judge/views/user.py:290
#: judge/views/user.py:291
msgid "Updated on site"
msgstr "Được cập nhật trên web"
#: judge/views/user.py:324 templates/admin/auth/user/change_form.html:14
#: templates/admin/auth/user/change_form.html:17 templates/base.html:255
#: judge/views/user.py:326 templates/admin/auth/user/change_form.html:14
#: templates/admin/auth/user/change_form.html:17 templates/base.html:297
#: templates/user/user-tabs.html:10
msgid "Edit profile"
msgstr "Chỉnh sửa thông tin"
#: judge/views/user.py:333 templates/user/user-list-tabs.html:4
#: judge/views/user.py:335 templates/user/user-list-tabs.html:4
msgid "Leaderboard"
msgstr "Bảng xếp hạng"
#: judge/views/user.py:408
#: judge/views/user.py:410
msgid "Import Users"
msgstr ""
@ -3197,20 +3197,20 @@ msgstr "Chỉnh sửa thông tin"
msgid "Rejudge"
msgstr "Chấm lại"
#: templates/base.html:224 templates/chat/chat.html:566
#: templates/base.html:266 templates/chat/chat.html:566
msgid "Chat"
msgstr "Chat"
#: templates/base.html:230
#: templates/base.html:272
msgid "Notification"
msgstr "Thông báo"
#: templates/base.html:247
#: templates/base.html:289
#, python-format
msgid "Hello, <b>%(username)s</b>."
msgstr "Xin chào, <b>%(username)s</b>."
#: templates/base.html:253 templates/chat/chat.html:20
#: templates/base.html:295 templates/chat/chat.html:20
#: templates/comments/list.html:89 templates/contest/contest-list-tabs.html:24
#: templates/contest/ranking-table.html:53
#: templates/problem/problem-list-tabs.html:6
@ -3219,28 +3219,36 @@ msgstr "Xin chào, <b>%(username)s</b>."
msgid "Admin"
msgstr ""
#: templates/base.html:262
#: templates/base.html:304
msgid "Log out"
msgstr "Đăng xuất"
#: templates/base.html:271
#: templates/base.html:313
#: templates/registration/password_reset_complete.html:4
msgid "Log in"
msgstr "Đăng nhập"
#: templates/base.html:272 templates/registration/registration_form.html:177
#: templates/base.html:314 templates/registration/registration_form.html:177
msgid "or"
msgstr "hoặc"
#: templates/base.html:273
#: templates/base.html:315
msgid "Sign up"
msgstr "Đăng ký"
#: templates/base.html:288
#: templates/base.html:331
msgid "spectating"
msgstr "đang theo dõi"
#: templates/base.html:301
#: templates/base.html:343
msgid "Compete"
msgstr "Thi"
#: templates/base.html:345
msgid "General"
msgstr "Chung"
#: templates/base.html:352
msgid "This site works best with JavaScript enabled."
msgstr ""
@ -4638,12 +4646,12 @@ msgid "Default language"
msgstr "Ngôn ngữ ưa thích"
#: templates/registration/registration_form.html:186
#: templates/user/edit-profile.html:181
#: templates/user/edit-profile.html:183
msgid "Affiliated organizations"
msgstr "Tổ chức bạn muốn tham gia"
#: templates/registration/registration_form.html:195
#: templates/user/edit-profile.html:136
#: templates/user/edit-profile.html:138
msgid "Notify me about upcoming contests"
msgstr "Nhận thông báo về các kỳ thi tương lai"
@ -4986,55 +4994,55 @@ msgstr "Không có gì."
msgid "Rank"
msgstr "Rank"
#: templates/user/edit-profile.html:98
#: templates/user/edit-profile.html:99
msgid "Name and School"
msgstr "Họ tên và Trường"
#: templates/user/edit-profile.html:100
#: templates/user/edit-profile.html:101
msgid "Enter this form"
msgstr "Điền vào link này"
#: templates/user/edit-profile.html:101
#: templates/user/edit-profile.html:102
msgid "It takes some time for admin to approve"
msgstr "Ban quản trị sẽ phê duyệt"
#: templates/user/edit-profile.html:105
#: templates/user/edit-profile.html:107
msgid "Self-description"
msgstr "Tự giới thiệu"
#: templates/user/edit-profile.html:113
#: templates/user/edit-profile.html:115
msgid "Select your closest major city"
msgstr "Chọn thành phố gần nhất"
#: templates/user/edit-profile.html:122
#: templates/user/edit-profile.html:124
msgid "Editor theme"
msgstr "Giao diện cho code editor"
#: templates/user/edit-profile.html:127
#: templates/user/edit-profile.html:129
msgid "Math engine"
msgstr ""
#: templates/user/edit-profile.html:151 templates/user/edit-profile.html:152
#: templates/user/edit-profile.html:153 templates/user/edit-profile.html:154
msgid "Change your avatar"
msgstr "Đổi ảnh đại diện"
#: templates/user/edit-profile.html:158
#: templates/user/edit-profile.html:160
msgid "Change your password"
msgstr "Đổi mật khẩu"
#: templates/user/edit-profile.html:165
#: templates/user/edit-profile.html:167
msgid "Two Factor Authentication is enabled."
msgstr "Two Factor Authentication đã được kích hoạt."
#: templates/user/edit-profile.html:172
#: templates/user/edit-profile.html:174
msgid "Two Factor Authentication is disabled."
msgstr "Two Factor Authentication đã được hủy kích hoạt."
#: templates/user/edit-profile.html:189
#: templates/user/edit-profile.html:191
msgid "User-script"
msgstr ""
#: templates/user/edit-profile.html:193
#: templates/user/edit-profile.html:195
msgid "Update profile"
msgstr "Cập nhật thông tin"

View file

@ -485,12 +485,8 @@ noscript #noscript {
#contest-info {
font-size: 1.25em;
border: 5px solid $highlight_blue;
border-left: 5px dotted white;
border-radius: 0 $widget_border_radius $widget_border_radius 0;
background: rgba(0, 0, 0, 0.77);
z-index: 100000;
padding: 10px 12px;
color: white;
cursor: move;
position: fixed;
left: 20px;
@ -506,6 +502,34 @@ noscript #noscript {
}
}
#contest-info-main {
border-left: 5px dotted white;
background: rgba(0, 0, 0, 0.77);
padding: 10px 12px;
color: white;
display: inline;
}
#contest-info-toggle {
display: inline;
padding: 10px 12px;
border-radius: 0 10px 10px 0;
cursor: pointer;
}
.contest-info-toggle-mode-on {
background: rgba(0, 205, 0, 0.57);
}
.contest-info-toggle-mode-on:hover {
background: rgba(0, 205, 0, 0.97);
}
.contest-info-toggle-mode-off {
background: rgba(255, 0, 0, 0.57);
}
.contest-info-toggle-mode-off:hover {
background: rgba(255, 0, 0, 0.97);
}
#contest-time-remaining {
display: inline-block;
}

View file

@ -2,6 +2,7 @@
margin: 0;
padding-top: 0.1em;
padding-bottom: 0.1em;
overflow-wrap: anywhere;
}
.chatbtn_remove_mess {
float: right;
@ -60,14 +61,13 @@
#chat-input {
width: 100%;
padding: 0.4em;
padding-bottom: 0.6em;
padding: 0.4em 4em 0.6em 1.2em;
border: 0;
color: black;
border-top-left-radius: 0;
border-top-right-radius: 0;
height: 100%;
font-size: 14px;
font-size: 16px;
}
#chat-online-content {
padding: 0;
@ -172,6 +172,20 @@
cursor: pointer;
margin-top: 0.5em;
}
.message-text {
padding: 0.4em 0.6em 0.5em;
border-radius: 15px;
max-width: 70%;
width: fit-content;
}
.message-text-other {
background: #eeeeee;
color: black;
}
.message-text-myself {
background: rgb(0, 132, 255);
color: white;
}
@media (max-width: 799px) {
#chat-area {

View file

@ -94,7 +94,9 @@
{% block js_media %}{% endblock %}
{% if request.in_contest %}
<script>$(function () {
count_down($("#contest-time-remaining"));
if ($("#contest-time-remaining").length) {
count_down($("#contest-time-remaining"));
}
var selected = null,
x_pos = 0, y_pos = 0,
@ -117,6 +119,12 @@
$("#contest-info").show();
$("#contest-info-toggle").on('click', function() {
$.post("{{url('contest_mode_ajax')}}", function() {
window.location.reload();
})
});
$(document).mousemove(function (e) {
x_pos = e.screenX;
y_pos = e.screenY;
@ -190,6 +198,42 @@
</style>
</noscript>
<style>
#contest-info {
font-size: 1.25em;
border: 5px solid $highlight_blue;
border-radius: 0 $widget_border_radius $widget_border_radius 0;
z-index: 100000;
cursor: move;
position: fixed;
left: 20px;
top: 90%;
display: none;
}
#contest-info-main {
border-left: 5px dotted white;
background: rgba(0, 0, 0, 0.77);
padding: 10px 12px;
color: white;
display: inline;
}
#contest-info-toggle {
display: inline;
padding: 10px 12px;
border-radius: 0 10px 10px 0;
cursor: pointer;
}
.contest-info-toggle-mode-on {
background: rgba(0, 205, 0, 0.57);
}
.contest-info-toggle-mode-on:hover {
background: rgba(0, 205, 0, 0.97);
}
.contest-info-toggle-mode-off {
background: rgba(255, 0, 0, 0.57);
}
.contest-info-toggle-mode-off:hover {
background: rgba(255, 0, 0, 0.97);
}
</style>
</head>
<body>
@ -284,18 +328,27 @@
</nav>
{% if request.in_contest %}
<div id="contest-info">
<a href="{{ url('contest_view', request.participation.contest.key) }}" style="vertical-align: middle">
{{ request.participation.contest.name }} -
{% if request.participation.spectate %}
{{ _('spectating') }}
{% elif request.participation.end_time %}
<div id="contest-time-remaining" data-secs="{{request.participation.end_time}}">
{{ request.participation.time_remaining|timedelta("localized") }}
</div>
<div id="contest-info-main">
<a href="{{ url('contest_view', request.participation.contest.key) }}" style="vertical-align: middle; display: inline">
{{ request.participation.contest.name }} -
{% if request.participation.spectate %}
{{ _('spectating') }}
{% elif request.participation.end_time %}
<div id="contest-time-remaining" data-secs="{{request.participation.end_time}}">
{{ request.participation.time_remaining|timedelta("localized") }}
</div>
{% else %}
{{ _('virtual') }}
{% endif %}
</a>
</div>
<div id="contest-info-toggle" class="{{'contest-info-toggle-mode-on' if request.contest_mode else 'contest-info-toggle-mode-off'}}">
{% if request.contest_mode %}
<i class="fa fa-toggle-on" style="color: white"></i> {{_('Compete')}}
{% else %}
{{ _('virtual') }}
<i class="fa fa-toggle-off" style="color: white"></i> {{_('General')}}
{% endif %}
</a>
</div>
</div>
{% endif %}
<div id="page-container">

View file

@ -110,7 +110,7 @@
</div>
<div class="blog-sidebar">
{% if request.in_contest and request.participation.contest.use_clarifications %}
{% if request.in_contest_mode and request.participation.contest.use_clarifications %}
<div class="blog-sidebox sidebox">
<h3>{{ _('Clarifications') }}
<i class="fa fa-question-circle"></i>

View file

@ -206,6 +206,7 @@ let META_HEADER = [
MathJax.Hub.Queue(["Typeset",MathJax.Hub]);
register_time($('.time-with-rel'));
remove_unread_current_user();
merge_authors();
},
error: function (data) {
console.log('Fail to check message');
@ -230,6 +231,12 @@ let META_HEADER = [
var time = moment($(this).find(".time-with-rel").attr('data-iso'));
var $content = $(this).children('.content-message');
if (username == window.user.name) {
$(this).find('.message-text').each(function() {
$(this).removeClass('message-text-other').addClass('message-text-myself');
});
}
if (username == last.username && time.diff(last.time, 'minutes') <= time_limit) {
last.$content.append($body);
$(this).parent().remove();

View file

@ -92,10 +92,8 @@
}
.body-block {
border-radius: 4px;
padding-left: 0.2em;
}
.body-block:hover {
background: #eee;
padding: 0.05em 0.6em;
width: 100%;
}
.active-span {
margin-top: 1em;

View file

@ -20,7 +20,9 @@
{{_('Delete')}}
</a>
{% endif %}
{{message.body | markdown('comment', MATH_ENGINE)|reference|str|safe }}
<div class="message-text message-text-other">
{{message.body | markdown('comment', MATH_ENGINE)|reference|str|safe }}
</div>
</div>
</span>
</div>

View file

@ -319,6 +319,31 @@
}
}
function get_initial_rank() {
var ranks = $('.rank-td').map(function() {return this.innerHTML}).get();
var usernames = $('.user-name .rating a').map(function() {return this.text}).get();
window.user_rank = new Map();
for (var i = 0; i < ranks.length; i++) {
window.user_rank[usernames[i]] = ranks[i];
}
}
function add_initial_friend_rank() {
var usernames = $('.user-name .rating a').map(function() {return this.text}).get();
var is_virtual = [];
$('.user-name').each(function() {
if($(this).children('sup').length) {
is_virtual.push(1);
}
else is_virtual.push(0);
});
$('.rank-td').each(function(i) {
if (!is_virtual[i]) this.innerHTML += ' (' + window.user_rank[usernames[i]] + ')';
});
}
function update_ranking() {
var friend = $('#show-friends-checkbox').is(':checked');
var virtual = $('#show-virtual-checkbox').is(':checked');
@ -328,8 +353,13 @@
success: function(HTML) {
$('#users-table').html(HTML);
highlightFirstSolve();
renew_filter();
$('#loading-gif').hide();
if (!virtual && !friend) {
get_initial_rank();
}
if (friend) {
add_initial_friend_rank();
}
},
fail: function() {
console.log('Fail to update ranking');
@ -394,6 +424,7 @@
highlightFirstSolve();
renew_filter();
get_initial_rank();
{% if participation_tab %}
$('#show-virtual-checkbox').hide();
$('#show-virtual-label').hide();

View file

@ -9,7 +9,7 @@
}
</style>
</noscript>
{% if not request.in_contest %}
{% if not request.in_contest_mode %}
<style>
#search-org {
width: 100%;
@ -131,7 +131,7 @@
});
</script>
{% endcompress %}
{% if request.in_contest %}
{% if request.in_contest_mode %}
{% compress js %}
<script src="{{ static('libs/tablesorter.js') }}" type="text/javascript"></script>
<script type="text/javascript">
@ -184,7 +184,7 @@
<div id="common-content">
{% block before_table %}{% endblock %}
{% if not request.in_contest %}
{% if not request.in_contest_mode %}
<div id="content-right" class="problems">
<div class="info-float">
{% include "problem/search-form.html" %}
@ -207,7 +207,7 @@
<table id="problem-table" class="table striped">
<thead>
<tr>
{% if request.in_contest %}
{% if request.in_contest_mode %}
{% if request.user.is_authenticated %}
<th class="solved"><i class="fa fa-check"></i></th>
{% endif %}
@ -268,7 +268,7 @@
{% 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 %}
{% 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>
@ -278,7 +278,7 @@
{% 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 %}
{% 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>
@ -287,7 +287,7 @@
</td>
{% else %}
<td solved="-1">
{% if problem.is_public or request.in_contest %}
{% 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>
@ -312,12 +312,12 @@
</td>
{% endif %}
<td class="p">{{ problem.points|floatformat }}{% if problem.partial %}p{% endif %}</td>
{% if not request.in_contest %}
{% 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 or not hide_contest_scoreboard %}
{% if not request.in_contest_mode or not hide_contest_scoreboard %}
{{ problem.user_count }}
{% else %}
???
@ -335,7 +335,7 @@
{% endfor %}
</tbody>
</table>
{% if request.in_contest and request.participation.contest.use_clarifications %}
{% 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">

View file

@ -58,7 +58,7 @@
{% endblock %}
{% block content_js_media %}
{% if request.in_contest %}
{% if request.in_contest_mode %}
<script type="text/javascript">
window.register_contest_notification("{{url('contest_clarification_ajax', request.participation.contest.key)}}");
</script>
@ -88,7 +88,7 @@
{% if request.user.is_authenticated %}
{% if problem.id in completed_problem_ids %}
<a href="{{ url('user_submissions', problem.code, request.user.username) }}">
{% if problem.is_public or request.in_contest %}
{% if problem.is_public or request.in_contest_mode %}
<i class="solved-problem-color title-state fa fa-check-circle"></i>
{% else %}
<i class="solved-problem-color title-state fa fa-lock"></i>
@ -96,7 +96,7 @@
</a>
{% elif problem.id in attempted_problems %}
<a href="{{ url('user_submissions', problem.code, request.user.username) }}">
{% if problem.is_public or request.in_contest %}
{% if problem.is_public or request.in_contest_mode %}
<i class="attempted-problem-color title-state fa fa-minus-circle"></i>
{% else %}
<i class="attempted-problem-color title-state fa fa-lock"></i>
@ -133,7 +133,7 @@
{% endblock %}
{% block info_float %}
{% if request.user.is_authenticated and request.in_contest and submission_limit %}
{% if request.user.is_authenticated and request.in_contest_mode and submission_limit %}
{% if submissions_left > 0 %}
<a href="{{ url('problem_submit', problem.code) }}" class="unselectable button full">
{{ _('Submit solution') }}

View file

@ -1,4 +1,4 @@
{% if request.in_contest and request.participation.contest.logo_override_image %}
{% if request.in_contest_mode and request.participation.contest.logo_override_image %}
<img src="{{ request.participation.contest.logo_override_image|camo }}" alt="{{ SITE_NAME }}" height="44" style="border: none">
{% elif logo_override_image is defined and logo_override_image %}
<img src="{{ logo_override_image|camo }}" alt="{{ SITE_NAME }}" height="44" style="border: none">

View file

@ -2,7 +2,7 @@
{% block js_media %}
<script type="text/javascript">
{% if dynamic_update and last_msg %}
{% if request.in_contest %}
{% if request.in_contest_mode %}
window.current_contest = '{{request.participation.contest.key}}';
{% else %}
window.current_contest = null;

View file

@ -24,7 +24,7 @@
<div>
{{ link_user(submission.user) }}
<span class="time">{{ relative_time(submission.date) }}</span>
{% if not request.in_contest and submission.contest_object_id %}
{% if not request.in_contest_mode and submission.contest_object_id %}
<a href="{{ url('contest_view', submission.contest_object.key) }}"
class="submission-contest">
<i title="{{ submission.contest_object.name }}" class="fa fa-dot-circle-o"></i>

View file

@ -32,10 +32,10 @@
<tr id="overall-row" class="case-row overall-result-{{submission.result}}">
<td><span class="col-title">{{_('Overall: ')}}</span>
{% if request.in_contest and submission.contest_or_none %}
{% if request.in_contest_mode and submission.contest_or_none %}
{% with contest=submission.contest_or_none %}
({{ _('%(points)s/%(total)s points', points=contest.points|roundfloat(3),
total=contest.problem.points|floatformat(-1)) }})
{{ _('%(points)s/%(total)s', points=contest.points|roundfloat(3),
total=contest.problem.points|floatformat(-1)) }}
{% endwith %}
{% else %}
{{ _('%(points)s/%(total)s', points=submission.points|roundfloat(3),