Design organization list page and add organization search (#119)

This commit is contained in:
Phuoc Anh Kha Le 2024-06-18 22:11:36 -05:00 committed by GitHub
parent 02ba30a29e
commit 326b3d5dd3
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
20 changed files with 553 additions and 286 deletions

View file

@ -168,7 +168,7 @@ else:
}, },
{ {
"model": "judge.Submission", "model": "judge.Submission",
"icon": "fa-check-square-o", "icon": "fa-check-square",
"children": [ "children": [
"judge.Language", "judge.Language",
"judge.Judge", "judge.Judge",

View file

@ -159,6 +159,8 @@ class ContestList(
def get_default_sort_order(self, request): def get_default_sort_order(self, request):
if request.GET.get("contest") and settings.ENABLE_FTS: if request.GET.get("contest") and settings.ENABLE_FTS:
return "-relevance" return "-relevance"
if self.current_tab == "future":
return "start_time"
return "-start_time" return "-start_time"
@cached_property @cached_property
@ -279,12 +281,24 @@ class ContestList(
return ( return (
self._get_queryset() self._get_queryset()
.filter(start_time__gt=self._now) .filter(start_time__gt=self._now)
.order_by("start_time", "key") .order_by(self.order, "key")
) )
def _get_active_participations_queryset(self): def _get_active_participations_queryset(self):
active_contests = self._get_queryset().filter(id__in=self._active_contests_ids) active_contests = (
return self._active_participations().filter(contest_id__in=active_contests) self._get_queryset()
.filter(id__in=self._active_contests_ids)
.order_by(self.order, "key")
)
ordered_ids = list(active_contests.values_list("id", flat=True))
participations = self._active_participations().filter(
contest_id__in=ordered_ids
)
participations = sorted(
participations, key=lambda p: ordered_ids.index(p.contest_id)
)
return participations
def get_queryset(self): def get_queryset(self):
if self.current_tab == "past": if self.current_tab == "past":
@ -303,7 +317,7 @@ class ContestList(
context["current_count"] = self._get_current_contests_queryset().count() context["current_count"] = self._get_current_contests_queryset().count()
context["future_count"] = self._get_future_contests_queryset().count() context["future_count"] = self._get_future_contests_queryset().count()
context["active_count"] = self._get_active_participations_queryset().count() context["active_count"] = len(self._get_active_participations_queryset())
context["now"] = self._now context["now"] = self._now
context["first_page_href"] = "." context["first_page_href"] = "."

View file

@ -238,33 +238,87 @@ class OrganizationHomeView(OrganizationMixin):
return context return context
class OrganizationList(TitleMixin, ListView, OrganizationBase): class OrganizationList(
QueryStringSortMixin, DiggPaginatorMixin, TitleMixin, ListView, OrganizationBase
):
model = Organization model = Organization
context_object_name = "organizations" context_object_name = "organizations"
template_name = "organization/list.html" template_name = "organization/list.html"
title = gettext_lazy("Groups") title = gettext_lazy("Groups")
paginate_by = 12
all_sorts = frozenset(("name", "member_count"))
default_desc = frozenset(("name", "member_count"))
def get_queryset(self): def get_default_sort_order(self, request):
return ( return "-member_count"
def get(self, request, *args, **kwargs):
default_tab = "mine"
if not self.request.user.is_authenticated:
default_tab = "public"
self.current_tab = self.request.GET.get("tab", default_tab)
self.organization_query = request.GET.get("organization", "")
return super(OrganizationList, self).get(request, *args, **kwargs)
def _get_queryset(self):
queryset = (
super(OrganizationList, self) super(OrganizationList, self)
.get_queryset() .get_queryset()
.annotate(member_count=Count("member")) .annotate(member_count=Count("member"))
.defer("about") .defer("about")
) )
def get_context_data(self, **kwargs): if self.organization_query:
context = super(OrganizationList, self).get_context_data(**kwargs) queryset = queryset.filter(
context["my_organizations"] = [] Q(slug__icontains=self.organization_query)
context["page_type"] = "organizations" | Q(name__icontains=self.organization_query)
| Q(short_name__icontains=self.organization_query)
)
return queryset
def get_queryset(self):
organization_list = self._get_queryset()
my_organizations = []
if self.request.profile: if self.request.profile:
context["my_organizations"] = context["organizations"].filter( my_organizations = organization_list.filter(
id__in=self.request.profile.organizations.values("id") id__in=self.request.profile.organizations.values("id")
) )
other_organizations = context["organizations"].exclude(
id__in=context["my_organizations"] if self.current_tab == "public":
) queryset = organization_list.exclude(id__in=my_organizations).filter(
context["open_organizations"] = other_organizations.filter(is_open=True) is_open=True
context["private_organizations"] = other_organizations.filter(is_open=False) )
elif self.current_tab == "private":
queryset = organization_list.exclude(id__in=my_organizations).filter(
is_open=False
)
else:
queryset = my_organizations
if queryset:
queryset = queryset.order_by(self.order)
return queryset
def get_context_data(self, **kwargs):
context = super(OrganizationList, self).get_context_data(**kwargs)
context["first_page_href"] = "."
context["current_tab"] = self.current_tab
context["page_type"] = self.current_tab
context["organization_query"] = self.organization_query
context["selected_order"] = self.request.GET.get("order")
context["all_sort_options"] = [
("name", _("Name (asc.)")),
("-name", _("Name (desc.)")),
("member_count", _("Member count (asc.)")),
("-member_count", _("Member count (desc.)")),
]
context.update(self.get_sort_context())
context.update(self.get_sort_paginate_context())
return context return context

View file

@ -2,7 +2,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: lqdoj2\n" "Project-Id-Version: lqdoj2\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2024-06-10 12:41+0700\n" "POT-Creation-Date: 2024-06-19 05:23+0700\n"
"PO-Revision-Date: 2021-07-20 03:44\n" "PO-Revision-Date: 2021-07-20 03:44\n"
"Last-Translator: Icyene\n" "Last-Translator: Icyene\n"
"Language-Team: Vietnamese\n" "Language-Team: Vietnamese\n"
@ -46,7 +46,7 @@ msgstr ""
msgid "Recent" msgid "Recent"
msgstr "Gần đây" msgstr "Gần đây"
#: chat_box/views.py:448 templates/base.html:197 #: chat_box/views.py:448 templates/base.html:196
#: templates/comments/content-list.html:72 #: templates/comments/content-list.html:72
#: templates/contest/contest-list-tabs.html:6 #: templates/contest/contest-list-tabs.html:6
#: templates/contest/ranking-table.html:52 templates/course/left_sidebar.html:8 #: templates/contest/ranking-table.html:52 templates/course/left_sidebar.html:8
@ -87,7 +87,7 @@ msgstr "Đăng ký không thành công"
msgid "Login" msgid "Login"
msgstr "Đăng nhập" msgstr "Đăng nhập"
#: dmoj/urls.py:221 templates/base.html:119 #: dmoj/urls.py:221 templates/base.html:118
#: templates/course/left_sidebar.html:2 #: templates/course/left_sidebar.html:2
#: templates/organization/org-left-sidebar.html:2 #: templates/organization/org-left-sidebar.html:2
msgid "Home" msgid "Home"
@ -126,7 +126,7 @@ msgstr ""
msgid "Problem" msgid "Problem"
msgstr "Bài tập" msgstr "Bài tập"
#: judge/admin/contest.py:183 templates/base.html:212 #: judge/admin/contest.py:183 templates/base.html:211
msgid "Settings" msgid "Settings"
msgstr "Cài đặt" msgstr "Cài đặt"
@ -197,7 +197,7 @@ msgstr "Tính toán lại kết quả"
msgid "username" msgid "username"
msgstr "tên đăng nhập" msgstr "tên đăng nhập"
#: judge/admin/contest.py:540 templates/base.html:252 #: judge/admin/contest.py:540 templates/base.html:251
msgid "virtual" msgid "virtual"
msgstr "ảo" msgstr "ảo"
@ -267,7 +267,7 @@ msgid "Limits"
msgstr "Giới hạn" msgstr "Giới hạn"
#: judge/admin/problem.py:232 judge/admin/submission.py:351 #: judge/admin/problem.py:232 judge/admin/submission.py:351
#: templates/base.html:163 templates/stats/tab.html:4 #: templates/base.html:162 templates/stats/tab.html:4
#: templates/submission/list.html:346 #: templates/submission/list.html:346
msgid "Language" msgid "Language"
msgstr "Ngôn ngữ" msgstr "Ngôn ngữ"
@ -427,9 +427,9 @@ msgstr[0] "%d bài nộp đã được tính điểm lại."
msgid "Rescore the selected submissions" msgid "Rescore the selected submissions"
msgstr "Tính điểm lại cái bài nộp" msgstr "Tính điểm lại cái bài nộp"
#: judge/admin/submission.py:332 templates/contest/list.html:215 #: judge/admin/submission.py:332 templates/contest/list.html:174
#: templates/contest/list.html:257 templates/contest/list.html:294 #: templates/contest/list.html:216 templates/contest/list.html:253
#: templates/contest/list.html:328 templates/notification/list.html:12 #: templates/contest/list.html:287 templates/notification/list.html:12
#: templates/organization/requests/log.html:10 #: templates/organization/requests/log.html:10
#: templates/organization/requests/pending.html:20 #: templates/organization/requests/pending.html:20
#: templates/problem/list.html:154 #: templates/problem/list.html:154
@ -642,26 +642,18 @@ msgid "votes"
msgstr "bình chọn" msgstr "bình chọn"
#: judge/models/bookmark.py:30 #: judge/models/bookmark.py:30
#, fuzzy
#| msgid "Bookmark"
msgid "bookmark" msgid "bookmark"
msgstr "Lưu" msgstr "Lưu"
#: judge/models/bookmark.py:31 #: judge/models/bookmark.py:31
#, fuzzy
#| msgid "Bookmark"
msgid "bookmarks" msgid "bookmarks"
msgstr "Lưu" msgstr "Lưu"
#: judge/models/bookmark.py:52 #: judge/models/bookmark.py:52
#, fuzzy
#| msgid "Bookmark"
msgid "make bookmark" msgid "make bookmark"
msgstr "Lưu" msgstr "Lưu"
#: judge/models/bookmark.py:53 #: judge/models/bookmark.py:53
#, fuzzy
#| msgid "Bookmark"
msgid "make bookmarks" msgid "make bookmarks"
msgstr "Lưu" msgstr "Lưu"
@ -686,8 +678,6 @@ msgid "comments"
msgstr "" msgstr ""
#: judge/models/comment.py:125 #: judge/models/comment.py:125
#, fuzzy
#| msgid "Editorial for {0}"
msgid "Editorial for " msgid "Editorial for "
msgstr "Hướng dẫn cho {0}" msgstr "Hướng dẫn cho {0}"
@ -1115,14 +1105,10 @@ msgid "same as format_data, but including frozen results"
msgstr "" msgstr ""
#: judge/models/contest.py:721 #: judge/models/contest.py:721
#, fuzzy
#| msgid "score"
msgid "final score" msgid "final score"
msgstr "điểm" msgstr "điểm"
#: judge/models/contest.py:723 #: judge/models/contest.py:723
#, fuzzy
#| msgid "cumulative time"
msgid "final cumulative time" msgid "final cumulative time"
msgstr "tổng thời gian" msgstr "tổng thời gian"
@ -1199,8 +1185,6 @@ msgstr ""
"Chỉ dùng với format IOI mới. Các sub cách nhau bởi dấu phẩy. Ví dụ: 2, 3" "Chỉ dùng với format IOI mới. Các sub cách nhau bởi dấu phẩy. Ví dụ: 2, 3"
#: judge/models/contest.py:848 #: judge/models/contest.py:848
#, fuzzy
#| msgid "frozen subtasks"
msgid "hidden subtasks" msgid "hidden subtasks"
msgstr "Đóng băng subtasks" msgstr "Đóng băng subtasks"
@ -2808,8 +2792,8 @@ msgstr "Bạn phải giải ít nhất 1 bài trước khi được vote."
msgid "You already voted." msgid "You already voted."
msgstr "Bạn đã vote." msgstr "Bạn đã vote."
#: judge/views/comment.py:267 judge/views/organization.py:820 #: judge/views/comment.py:267 judge/views/organization.py:872
#: judge/views/organization.py:970 judge/views/organization.py:1149 #: judge/views/organization.py:1022 judge/views/organization.py:1201
msgid "Edited from site" msgid "Edited from site"
msgstr "Chỉnh sửa từ web" msgstr "Chỉnh sửa từ web"
@ -2834,156 +2818,156 @@ msgstr "Bạn phải giải ít nhất một bài trước khi được phép b
msgid "Posted comment" msgid "Posted comment"
msgstr "Bình luận đã đăng" msgstr "Bình luận đã đăng"
#: judge/views/contests.py:125 judge/views/contests.py:457 #: judge/views/contests.py:125 judge/views/contests.py:463
#: judge/views/contests.py:462 judge/views/contests.py:762 #: judge/views/contests.py:468 judge/views/contests.py:768
msgid "No such contest" msgid "No such contest"
msgstr "Không có contest nào như vậy" msgstr "Không có contest nào như vậy"
#: judge/views/contests.py:126 judge/views/contests.py:458 #: judge/views/contests.py:126 judge/views/contests.py:464
#, python-format #, python-format
msgid "Could not find a contest with the key \"%s\"." msgid "Could not find a contest with the key \"%s\"."
msgstr "Không tìm thấy kỳ thi với mã \"%s\"." msgstr "Không tìm thấy kỳ thi với mã \"%s\"."
#: judge/views/contests.py:154 judge/views/contests.py:1549 #: judge/views/contests.py:154 judge/views/contests.py:1555
#: judge/views/stats.py:178 templates/contest/list.html:211 #: judge/views/stats.py:178 templates/contest/list.html:170
#: templates/contest/list.html:253 templates/contest/list.html:290 #: templates/contest/list.html:212 templates/contest/list.html:249
#: templates/contest/list.html:324 #: templates/contest/list.html:283
#: templates/organization/org-left-sidebar.html:5 templates/stats/site.html:21 #: templates/organization/org-left-sidebar.html:5 templates/stats/site.html:21
#: templates/user/user-bookmarks.html:19 templates/user/user-bookmarks.html:80 #: templates/user/user-bookmarks.html:19 templates/user/user-bookmarks.html:80
msgid "Contests" msgid "Contests"
msgstr "Kỳ thi" msgstr "Kỳ thi"
#: judge/views/contests.py:318 #: judge/views/contests.py:324
msgid "Start time (asc.)" msgid "Start time (asc.)"
msgstr "Thời gian bắt đầu (tăng)" msgstr "Thời gian bắt đầu (tăng)"
#: judge/views/contests.py:319 #: judge/views/contests.py:325
msgid "Start time (desc.)" msgid "Start time (desc.)"
msgstr "Thời gian bắt đầu (giảm)" msgstr "Thời gian bắt đầu (giảm)"
#: judge/views/contests.py:320 #: judge/views/contests.py:326 judge/views/organization.py:311
msgid "Name (asc.)" msgid "Name (asc.)"
msgstr "Tên (tăng)" msgstr "Tên (tăng)"
#: judge/views/contests.py:321 #: judge/views/contests.py:327 judge/views/organization.py:312
msgid "Name (desc.)" msgid "Name (desc.)"
msgstr "Tên (giảm)" msgstr "Tên (giảm)"
#: judge/views/contests.py:322 #: judge/views/contests.py:328
msgid "User count (asc.)" msgid "User count (asc.)"
msgstr "Số lượng tham gia (tăng)" msgstr "Số lượng tham gia (tăng)"
#: judge/views/contests.py:323 #: judge/views/contests.py:329
msgid "User count (desc.)" msgid "User count (desc.)"
msgstr "Số lượng tham gia (giảm)" msgstr "Số lượng tham gia (giảm)"
#: judge/views/contests.py:462 #: judge/views/contests.py:468
msgid "Could not find such contest." msgid "Could not find such contest."
msgstr "Không tìm thấy kỳ thi nào như vậy." msgstr "Không tìm thấy kỳ thi nào như vậy."
#: judge/views/contests.py:470 #: judge/views/contests.py:476
#, python-format #, python-format
msgid "Access to contest \"%s\" denied" msgid "Access to contest \"%s\" denied"
msgstr "Truy cập tới kỳ thi \"%s\" bị từ chối" msgstr "Truy cập tới kỳ thi \"%s\" bị từ chối"
#: judge/views/contests.py:548 #: judge/views/contests.py:554
msgid "Clone Contest" msgid "Clone Contest"
msgstr "Nhân bản kỳ thi" msgstr "Nhân bản kỳ thi"
#: judge/views/contests.py:640 #: judge/views/contests.py:646
msgid "Contest not ongoing" msgid "Contest not ongoing"
msgstr "Kỳ thi đang không diễn ra" msgstr "Kỳ thi đang không diễn ra"
#: judge/views/contests.py:641 #: judge/views/contests.py:647
#, python-format #, python-format
msgid "\"%s\" is not currently ongoing." msgid "\"%s\" is not currently ongoing."
msgstr "\"%s\" kỳ thi đang không diễn ra." msgstr "\"%s\" kỳ thi đang không diễn ra."
#: judge/views/contests.py:654 #: judge/views/contests.py:660
msgid "Banned from joining" msgid "Banned from joining"
msgstr "Bị cấm tham gia" msgstr "Bị cấm tham gia"
#: judge/views/contests.py:656 #: judge/views/contests.py:662
msgid "" msgid ""
"You have been declared persona non grata for this contest. You are " "You have been declared persona non grata for this contest. You are "
"permanently barred from joining this contest." "permanently barred from joining this contest."
msgstr "Bạn không được phép tham gia kỳ thi này." msgstr "Bạn không được phép tham gia kỳ thi này."
#: judge/views/contests.py:746 #: judge/views/contests.py:752
#, python-format #, python-format
msgid "Enter access code for \"%s\"" msgid "Enter access code for \"%s\""
msgstr "Nhập mật khẩu truy cập cho \"%s\"" msgstr "Nhập mật khẩu truy cập cho \"%s\""
#: judge/views/contests.py:763 #: judge/views/contests.py:769
#, python-format #, python-format
msgid "You are not in contest \"%s\"." msgid "You are not in contest \"%s\"."
msgstr "Bạn không ở trong kỳ thi \"%s\"." msgstr "Bạn không ở trong kỳ thi \"%s\"."
#: judge/views/contests.py:786 #: judge/views/contests.py:792
msgid "ContestCalendar requires integer year and month" 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" msgstr "Lịch thi yêu cầu giá trị cho năm và tháng là số nguyên"
#: judge/views/contests.py:844 #: judge/views/contests.py:850
#, python-format #, python-format
msgid "Contests in %(month)s" msgid "Contests in %(month)s"
msgstr "Các kỳ thi trong %(month)s" msgstr "Các kỳ thi trong %(month)s"
#: judge/views/contests.py:845 #: judge/views/contests.py:851
msgid "F Y" msgid "F Y"
msgstr "F Y" msgstr "F Y"
#: judge/views/contests.py:905 #: judge/views/contests.py:911
#, python-format #, python-format
msgid "%s Statistics" msgid "%s Statistics"
msgstr "%s Thống kê" msgstr "%s Thống kê"
#: judge/views/contests.py:1231 #: judge/views/contests.py:1237
#, python-format #, python-format
msgid "%s Rankings" msgid "%s Rankings"
msgstr "%s Bảng điểm" msgstr "%s Bảng điểm"
#: judge/views/contests.py:1242 #: judge/views/contests.py:1248
msgid "???" msgid "???"
msgstr "???" msgstr "???"
#: judge/views/contests.py:1269 #: judge/views/contests.py:1275
#, python-format #, python-format
msgid "Your participation in %s" msgid "Your participation in %s"
msgstr "Lần tham gia trong %s" msgstr "Lần tham gia trong %s"
#: judge/views/contests.py:1270 #: judge/views/contests.py:1276
#, python-format #, python-format
msgid "%s's participation in %s" msgid "%s's participation in %s"
msgstr "Lần tham gia của %s trong %s" msgstr "Lần tham gia của %s trong %s"
#: judge/views/contests.py:1284 #: judge/views/contests.py:1290
msgid "Live" msgid "Live"
msgstr "Trực tiếp" msgstr "Trực tiếp"
#: judge/views/contests.py:1302 templates/contest/contest-tabs.html:21 #: judge/views/contests.py:1308 templates/contest/contest-tabs.html:21
msgid "Participation" msgid "Participation"
msgstr "Lần tham gia" msgstr "Lần tham gia"
#: judge/views/contests.py:1351 #: judge/views/contests.py:1357
#, python-format #, python-format
msgid "%s MOSS Results" msgid "%s MOSS Results"
msgstr "%s Kết quả MOSS" msgstr "%s Kết quả MOSS"
#: judge/views/contests.py:1387 #: judge/views/contests.py:1393
#, python-format #, python-format
msgid "Running MOSS for %s..." msgid "Running MOSS for %s..."
msgstr "Đang chạy MOSS cho %s..." msgstr "Đang chạy MOSS cho %s..."
#: judge/views/contests.py:1410 #: judge/views/contests.py:1416
#, python-format #, python-format
msgid "Contest tag: %s" msgid "Contest tag: %s"
msgstr "Nhãn kỳ thi: %s" msgstr "Nhãn kỳ thi: %s"
#: judge/views/contests.py:1425 judge/views/ticket.py:67 #: judge/views/contests.py:1431 judge/views/ticket.py:67
msgid "Issue description" msgid "Issue description"
msgstr "Mô tả vấn đề" msgstr "Mô tả vấn đề"
#: judge/views/contests.py:1468 #: judge/views/contests.py:1474
#, python-format #, python-format
msgid "New clarification for %s" msgid "New clarification for %s"
msgstr "Thông báo mới cho %s" msgstr "Thông báo mới cho %s"
@ -3117,81 +3101,89 @@ msgstr "Không thể chỉnh sửa tổ chức"
msgid "You are not allowed to edit this organization." msgid "You are not allowed to edit this organization."
msgstr "Bạn không được phép chỉnh sửa tổ chức này." msgstr "Bạn không được phép chỉnh sửa tổ chức này."
#: judge/views/organization.py:201 judge/views/organization.py:345 #: judge/views/organization.py:201 judge/views/organization.py:397
msgid "Can't access organization" msgid "Can't access organization"
msgstr "Không thể truy cập nhóm" msgstr "Không thể truy cập nhóm"
#: judge/views/organization.py:202 judge/views/organization.py:346 #: judge/views/organization.py:202 judge/views/organization.py:398
msgid "You are not allowed to access this organization." msgid "You are not allowed to access this organization."
msgstr "Bạn không được phép chỉnh sửa tổ chức này." msgstr "Bạn không được phép chỉnh sửa tổ chức này."
#: judge/views/organization.py:245 judge/views/stats.py:184 #: judge/views/organization.py:245 judge/views/stats.py:184
#: templates/contest/list.html:118 templates/problem/list-base.html:90 #: templates/contest/list.html:77 templates/problem/list-base.html:90
#: templates/stats/site.html:33 templates/user/user-left-sidebar.html:4 #: templates/stats/site.html:33 templates/user/user-left-sidebar.html:4
#: templates/user/user-list-tabs.html:6 #: templates/user/user-list-tabs.html:6
msgid "Groups" msgid "Groups"
msgstr "Nhóm" msgstr "Nhóm"
#: judge/views/organization.py:352 #: judge/views/organization.py:313
msgid "Member count (asc.)"
msgstr "Số lượng thành viên (tăng)"
#: judge/views/organization.py:314
msgid "Member count (desc.)"
msgstr "Số lượng thành viên (giảm)"
#: judge/views/organization.py:404
#, python-format #, python-format
msgid "%s Members" msgid "%s Members"
msgstr "%s Thành viên" msgstr "%s Thành viên"
#: judge/views/organization.py:474 #: judge/views/organization.py:526
#, python-brace-format #, python-brace-format
msgid "All submissions in <a href=\"{1}\">{0}</a>" msgid "All submissions in <a href=\"{1}\">{0}</a>"
msgstr "Bài nộp trong <a href=\"{1}\">{0}</a>" msgstr "Bài nộp trong <a href=\"{1}\">{0}</a>"
#: judge/views/organization.py:482 judge/views/submission.py:857 #: judge/views/organization.py:534 judge/views/submission.py:857
msgid "Submissions in" msgid "Submissions in"
msgstr "Bài nộp trong" msgstr "Bài nộp trong"
#: judge/views/organization.py:507 judge/views/organization.py:513 #: judge/views/organization.py:559 judge/views/organization.py:565
#: judge/views/organization.py:520 #: judge/views/organization.py:572
msgid "Joining group" msgid "Joining group"
msgstr "Tham gia nhóm" msgstr "Tham gia nhóm"
#: judge/views/organization.py:508 #: judge/views/organization.py:560
msgid "You are already in the group." msgid "You are already in the group."
msgstr "Bạn đã ở trong nhóm." msgstr "Bạn đã ở trong nhóm."
#: judge/views/organization.py:513 #: judge/views/organization.py:565
msgid "This group is not open." msgid "This group is not open."
msgstr "Nhóm này là nhóm kín." msgstr "Nhóm này là nhóm kín."
#: judge/views/organization.py:521 #: judge/views/organization.py:573
#, python-brace-format #, python-brace-format
msgid "You may not be part of more than {count} public groups." msgid "You may not be part of more than {count} public groups."
msgstr "Bạn không thể tham gia nhiều hơn {count} nhóm công khai." msgstr "Bạn không thể tham gia nhiều hơn {count} nhóm công khai."
#: judge/views/organization.py:537 #: judge/views/organization.py:589
msgid "Leaving group" msgid "Leaving group"
msgstr "Rời nhóm" msgstr "Rời nhóm"
#: judge/views/organization.py:538 #: judge/views/organization.py:590
#, python-format #, python-format
msgid "You are not in \"%s\"." msgid "You are not in \"%s\"."
msgstr "Bạn không ở trong \"%s\"." msgstr "Bạn không ở trong \"%s\"."
#: judge/views/organization.py:564 #: judge/views/organization.py:616
#, python-format #, python-format
msgid "Request to join %s" msgid "Request to join %s"
msgstr "Đăng ký tham gia %s" msgstr "Đăng ký tham gia %s"
#: judge/views/organization.py:594 #: judge/views/organization.py:646
msgid "Join request detail" msgid "Join request detail"
msgstr "Chi tiết đơn đăng ký" msgstr "Chi tiết đơn đăng ký"
#: judge/views/organization.py:636 #: judge/views/organization.py:688
msgid "Manage join requests" msgid "Manage join requests"
msgstr "Quản lý đơn đăng ký" msgstr "Quản lý đơn đăng ký"
#: judge/views/organization.py:640 #: judge/views/organization.py:692
#, python-format #, python-format
msgid "Managing join requests for %s" msgid "Managing join requests for %s"
msgstr "Quản lý đơn đăng ký cho %s" msgstr "Quản lý đơn đăng ký cho %s"
#: judge/views/organization.py:680 #: judge/views/organization.py:732
#, python-format #, python-format
msgid "" msgid ""
"Your organization can only receive %d more members. You cannot approve %d " "Your organization can only receive %d more members. You cannot approve %d "
@ -3200,81 +3192,81 @@ msgstr ""
"Tổ chức chỉ có thể chứa %d thành viên. Bạn không thể chấp thuận nhiều hơn %d " "Tổ chức chỉ có thể chứa %d thành viên. Bạn không thể chấp thuận nhiều hơn %d "
"người." "người."
#: judge/views/organization.py:698 #: judge/views/organization.py:750
#, python-format #, python-format
msgid "Approved %d user." msgid "Approved %d user."
msgid_plural "Approved %d users." msgid_plural "Approved %d users."
msgstr[0] "Đã chấp thuận %d người." msgstr[0] "Đã chấp thuận %d người."
#: judge/views/organization.py:701 #: judge/views/organization.py:753
#, python-format #, python-format
msgid "Rejected %d user." msgid "Rejected %d user."
msgid_plural "Rejected %d users." msgid_plural "Rejected %d users."
msgstr[0] "Đã từ chối %d người." msgstr[0] "Đã từ chối %d người."
#: judge/views/organization.py:741 #: judge/views/organization.py:793
#, python-format #, python-format
msgid "Add member for %s" msgid "Add member for %s"
msgstr "Thêm thành viên cho %s" msgstr "Thêm thành viên cho %s"
#: judge/views/organization.py:753 #: judge/views/organization.py:805
#, fuzzy #, fuzzy
#| msgid "Edited from site" #| msgid "Edited from site"
msgid "Added members from site" msgid "Added members from site"
msgstr "Chỉnh sửa từ web" msgstr "Chỉnh sửa từ web"
#: judge/views/organization.py:773 judge/views/organization.py:781 #: judge/views/organization.py:825 judge/views/organization.py:833
msgid "Can't kick user" msgid "Can't kick user"
msgstr "Không thể đuổi" msgstr "Không thể đuổi"
#: judge/views/organization.py:774 #: judge/views/organization.py:826
msgid "The user you are trying to kick does not exist!" msgid "The user you are trying to kick does not exist!"
msgstr "" msgstr ""
#: judge/views/organization.py:782 #: judge/views/organization.py:834
#, python-format #, python-format
msgid "The user you are trying to kick is not in organization: %s." msgid "The user you are trying to kick is not in organization: %s."
msgstr "" msgstr ""
#: judge/views/organization.py:803 judge/views/organization.py:959 #: judge/views/organization.py:855 judge/views/organization.py:1011
#, python-format #, python-format
msgid "Edit %s" msgid "Edit %s"
msgstr "Chỉnh sửa %s" msgstr "Chỉnh sửa %s"
#: judge/views/organization.py:831 templates/organization/list.html:46 #: judge/views/organization.py:883 templates/organization/search-form.html:19
msgid "Create group" msgid "Create group"
msgstr "Tạo nhóm" msgstr "Tạo nhóm"
#: judge/views/organization.py:846 #: judge/views/organization.py:898
msgid "Exceeded limit" msgid "Exceeded limit"
msgstr "" msgstr ""
#: judge/views/organization.py:847 #: judge/views/organization.py:899
#, python-format #, python-format
msgid "You created too many groups. You can only create at most %d groups" msgid "You created too many groups. You can only create at most %d groups"
msgstr "" msgstr ""
#: judge/views/organization.py:852 judge/views/organization.py:877 #: judge/views/organization.py:904 judge/views/organization.py:929
#: judge/views/organization.py:1050 #: judge/views/organization.py:1102
msgid "Added from site" msgid "Added from site"
msgstr "Thêm từ web" msgstr "Thêm từ web"
#: judge/views/organization.py:868 #: judge/views/organization.py:920
#: templates/organization/org-right-sidebar.html:47 #: templates/organization/org-right-sidebar.html:47
msgid "Add contest" msgid "Add contest"
msgstr "Thêm kỳ thi" msgstr "Thêm kỳ thi"
#: judge/views/organization.py:911 judge/views/organization.py:1100 #: judge/views/organization.py:963 judge/views/organization.py:1152
msgid "Permission denied" msgid "Permission denied"
msgstr "Truy cập bị từ chối" msgstr "Truy cập bị từ chối"
#: judge/views/organization.py:912 #: judge/views/organization.py:964
#, fuzzy #, fuzzy
#| msgid "You are not allowed to edit this organization." #| msgid "You are not allowed to edit this organization."
msgid "You are not allowed to edit this contest" msgid "You are not allowed to edit this contest"
msgstr "Bạn không được phép chỉnh sửa tổ chức này." msgstr "Bạn không được phép chỉnh sửa tổ chức này."
#: judge/views/organization.py:963 templates/blog/blog.html:31 #: judge/views/organization.py:1015 templates/blog/blog.html:31
#: templates/comments/content-list.html:53 #: templates/comments/content-list.html:53
#: templates/comments/content-list.html:66 #: templates/comments/content-list.html:66
#: templates/contest/contest-tabs.html:36 templates/contest/macros.html:14 #: templates/contest/contest-tabs.html:36 templates/contest/macros.html:14
@ -3285,21 +3277,21 @@ msgstr "Bạn không được phép chỉnh sửa tổ chức này."
msgid "Edit" msgid "Edit"
msgstr "Chỉnh sửa" msgstr "Chỉnh sửa"
#: judge/views/organization.py:1039 #: judge/views/organization.py:1091
#, python-format #, python-format
msgid "Add blog for %s" msgid "Add blog for %s"
msgstr "Thêm bài đăng cho %s" msgstr "Thêm bài đăng cho %s"
#: judge/views/organization.py:1101 #: judge/views/organization.py:1153
msgid "Not allowed to edit this blog" msgid "Not allowed to edit this blog"
msgstr "Bạn không được phép chỉnh sửa bài đăng này." msgstr "Bạn không được phép chỉnh sửa bài đăng này."
#: judge/views/organization.py:1133 #: judge/views/organization.py:1185
#, python-format #, python-format
msgid "Edit blog %s" msgid "Edit blog %s"
msgstr "Chỉnh sửa %s" msgstr "Chỉnh sửa %s"
#: judge/views/organization.py:1180 #: judge/views/organization.py:1232
#, python-format #, python-format
msgid "Pending blogs in %s" msgid "Pending blogs in %s"
msgstr "Bài đang đợi duyệt trong %s" msgstr "Bài đang đợi duyệt trong %s"
@ -3774,66 +3766,66 @@ msgstr "Chỉnh sửa thông tin"
msgid "Rejudge" msgid "Rejudge"
msgstr "Chấm lại" msgstr "Chấm lại"
#: templates/base.html:145 #: templates/base.html:144
msgid "Chat" msgid "Chat"
msgstr "Chat" msgstr "Chat"
#: templates/base.html:155 #: templates/base.html:154
msgid "Notification" msgid "Notification"
msgstr "Thông báo" msgstr "Thông báo"
#: templates/base.html:182 #: templates/base.html:181
msgid "Dark Mode" msgid "Dark Mode"
msgstr "" msgstr ""
#: templates/base.html:193 templates/profile-table.html:3 #: templates/base.html:192 templates/profile-table.html:3
msgid "Profile" msgid "Profile"
msgstr "Trang cá nhân" msgstr "Trang cá nhân"
#: templates/base.html:202 #: templates/base.html:201
msgid "Internal" msgid "Internal"
msgstr "Nội bộ" msgstr "Nội bộ"
#: templates/base.html:205 #: templates/base.html:204
msgid "Stats" msgid "Stats"
msgstr "Thống kê" msgstr "Thống kê"
#: templates/base.html:209 templates/user/user-tabs.html:11 #: templates/base.html:208 templates/user/user-tabs.html:11
msgid "Bookmarks" msgid "Bookmarks"
msgstr "Đã lưu" msgstr "Đã lưu"
#: templates/base.html:216 #: templates/base.html:215
#, fuzzy #, fuzzy
#| msgid "Stop spectating" #| msgid "Stop spectating"
msgid "Stop impersonating" msgid "Stop impersonating"
msgstr "Ngừng theo dõi" msgstr "Ngừng theo dõi"
#: templates/base.html:221 #: templates/base.html:220
msgid "Log out" msgid "Log out"
msgstr "Đăng xuất" msgstr "Đăng xuất"
#: templates/base.html:231 #: templates/base.html:230
#: templates/registration/password_reset_complete.html:4 #: templates/registration/password_reset_complete.html:4
msgid "Log in" msgid "Log in"
msgstr "Đăng nhập" msgstr "Đăng nhập"
#: templates/base.html:232 #: templates/base.html:231
msgid "Sign up" msgid "Sign up"
msgstr "Đăng ký" msgstr "Đăng ký"
#: templates/base.html:246 #: templates/base.html:245
msgid "spectating" msgid "spectating"
msgstr "đang theo dõi" msgstr "đang theo dõi"
#: templates/base.html:258 templates/contest/list.html:151 #: templates/base.html:257 templates/contest/list.html:110
msgid "In contest" msgid "In contest"
msgstr "Trong kỳ thi" msgstr "Trong kỳ thi"
#: templates/base.html:260 #: templates/base.html:259
msgid "Out contest" msgid "Out contest"
msgstr "Ngoài kỳ thi" msgstr "Ngoài kỳ thi"
#: templates/base.html:267 #: templates/base.html:266
msgid "This site works best with JavaScript enabled." msgid "This site works best with JavaScript enabled."
msgstr "" msgstr ""
@ -4215,7 +4207,7 @@ msgstr "MOSS"
msgid "Leave contest" msgid "Leave contest"
msgstr "Rời kỳ thi" msgstr "Rời kỳ thi"
#: templates/contest/contest.html:43 templates/contest/list.html:156 #: templates/contest/contest.html:43 templates/contest/list.html:115
msgid "Virtual join" msgid "Virtual join"
msgstr "Tham gia ảo" msgstr "Tham gia ảo"
@ -4262,11 +4254,11 @@ msgstr "Rank"
msgid "Name" msgid "Name"
msgstr "Tên" msgstr "Tên"
#: templates/contest/list.html:98 templates/contest/media-js.html:152 #: templates/contest/list.html:57 templates/contest/media-js.html:152
msgid "Are you sure you want to join?" msgid "Are you sure you want to join?"
msgstr "Bạn có chắc tham gia?" msgstr "Bạn có chắc tham gia?"
#: templates/contest/list.html:99 #: templates/contest/list.html:58
msgid "" msgid ""
"Joining a contest for the first time starts your timer, after which it " "Joining a contest for the first time starts your timer, after which it "
"becomes unstoppable." "becomes unstoppable."
@ -4274,57 +4266,58 @@ msgstr ""
"Tham gia kỳ thi lần đầu sẽ kích hoạt thời gian đếm ngược, không thể dừng lại " "Tham gia kỳ thi lần đầu sẽ kích hoạt thời gian đếm ngược, không thể dừng lại "
"sau đó." "sau đó."
#: templates/contest/list.html:101 templates/contest/media-js.html:155 #: templates/contest/list.html:60 templates/contest/media-js.html:155
msgid "By joining in this contest, you will automatically leave contest" msgid "By joining in this contest, you will automatically leave contest"
msgstr "Khi tham gia kỳ thi này, bạn sẽ tự động rời khỏi kỳ thi" msgstr "Khi tham gia kỳ thi này, bạn sẽ tự động rời khỏi kỳ thi"
#: templates/contest/list.html:162 #: templates/contest/list.html:121
msgid "Spectate" msgid "Spectate"
msgstr "Theo dõi" msgstr "Theo dõi"
#: templates/contest/list.html:168 templates/organization/home.html:23 #: templates/contest/list.html:127 templates/organization/home.html:23
#: templates/organization/list.html:72
msgid "Join" msgid "Join"
msgstr "Tham gia" msgstr "Tham gia"
#: templates/contest/list.html:178 #: templates/contest/list.html:137
msgid "Active" msgid "Active"
msgstr "Đang tham gia" msgstr "Đang tham gia"
#: templates/contest/list.html:186 #: templates/contest/list.html:145
msgid "Ongoing" msgid "Ongoing"
msgstr "Đang diễn ra" msgstr "Đang diễn ra"
#: templates/contest/list.html:193 #: templates/contest/list.html:152
msgid "Upcoming" msgid "Upcoming"
msgstr "Sắp diễn ra" msgstr "Sắp diễn ra"
#: templates/contest/list.html:200 #: templates/contest/list.html:159
msgid "Past" msgid "Past"
msgstr "Đã diễn ra" msgstr "Đã diễn ra"
#: templates/contest/list.html:221 #: templates/contest/list.html:180
#, python-format #, python-format
msgid "Window ends in %(countdown)s" msgid "Window ends in %(countdown)s"
msgstr "Cửa số thi còn %(countdown)s" msgstr "Cửa số thi còn %(countdown)s"
#: templates/contest/list.html:224 templates/contest/list.html:262 #: templates/contest/list.html:183 templates/contest/list.html:221
#, python-format #, python-format
msgid "Ends in %(countdown)s" msgid "Ends in %(countdown)s"
msgstr "Kết thúc trong %(countdown)s" msgstr "Kết thúc trong %(countdown)s"
#: templates/contest/list.html:244 #: templates/contest/list.html:203
msgid "There is no active contest at this time." msgid "There is no active contest at this time."
msgstr "Không có kỳ thi nào đang tham gia." msgstr "Không có kỳ thi nào đang tham gia."
#: templates/contest/list.html:281 #: templates/contest/list.html:240
msgid "There is no ongoing contest at this time." msgid "There is no ongoing contest at this time."
msgstr "Không có kỳ thi nào đang diễn ra hiện tại." msgstr "Không có kỳ thi nào đang diễn ra hiện tại."
#: templates/contest/list.html:315 #: templates/contest/list.html:274
msgid "There is no scheduled contest at this time." msgid "There is no scheduled contest at this time."
msgstr "Không có kỳ thi nào được lên lịch hiện tại." msgstr "Không có kỳ thi nào được lên lịch hiện tại."
#: templates/contest/list.html:347 #: templates/contest/list.html:306
msgid "There is no past contest." msgid "There is no past contest."
msgstr "Không có kỳ thi nào trong quá khứ." msgstr "Không có kỳ thi nào trong quá khứ."
@ -4436,12 +4429,15 @@ msgstr "Đến"
#: templates/contest/official-search-form.html:41 #: templates/contest/official-search-form.html:41
#: templates/contest/search-form.html:22 #: templates/contest/search-form.html:22
#: templates/organization/search-form.html:8
msgid "Order by" msgid "Order by"
msgstr "Sắp xếp theo" msgstr "Sắp xếp theo"
#: templates/contest/official-search-form.html:53 #: templates/contest/official-search-form.html:53
#: templates/contest/search-form.html:33 templates/problem/search-form.html:95 #: templates/contest/search-form.html:33
#: templates/submission/list.html:355 templates/ticket/list.html:250 #: templates/organization/search-form.html:20
#: templates/problem/search-form.html:95 templates/submission/list.html:355
#: templates/ticket/list.html:250
msgid "Go" msgid "Go"
msgstr "Lọc" msgstr "Lọc"
@ -4764,25 +4760,47 @@ msgstr "Bạn phải tham gia lại để được hiển thị trong bảng x
msgid "You will have to request membership in order to join again." msgid "You will have to request membership in order to join again."
msgstr "Bạn phải đăng ký thành viên để được tham gia lại." msgstr "Bạn phải đăng ký thành viên để được tham gia lại."
#: templates/organization/home.html:28 #: templates/organization/home.html:28 templates/organization/list.html:75
msgid "Request membership" msgid "Request membership"
msgstr "Đăng ký thành viên" msgstr "Đăng ký thành viên"
#: templates/organization/list.html:38 #: templates/organization/list.html:37 templates/submission/list.html:382
#: templates/submission/submission-list-tabs.html:6
msgid "Mine"
msgstr "Tôi"
#: templates/organization/list.html:39
msgid "Public"
msgstr "Nhóm mở"
#: templates/organization/list.html:40
msgid "Private"
msgstr "Nhóm kín"
#: templates/organization/list.html:42 templates/user/import/index.html:105
#: templates/user/user-left-sidebar.html:6 templates/user/user-list-tabs.html:8
msgid "Import"
msgstr ""
#: templates/organization/list.html:65
msgid "members" msgid "members"
msgstr "thành viên" msgstr "thành viên"
#: templates/organization/list.html:47 #: templates/organization/list.html:68
msgid "My groups" msgid "View"
msgstr "Nhóm của tôi" msgstr "Xem"
#: templates/organization/list.html:48 #: templates/organization/list.html:91
msgid "Open groups" msgid "You have not joined any organization yet."
msgstr "Nhóm mở" msgstr "Bạn chưa tham gia nhóm nào."
#: templates/organization/list.html:49 #: templates/organization/list.html:99
msgid "Private groups" msgid "There is no public organization."
msgstr "Nhóm kín" msgstr "Không có nhóm mở nào"
#: templates/organization/list.html:107
msgid "There is no private organization."
msgstr "Không có nhóm kín nào"
#: templates/organization/org-left-sidebar.html:9 #: templates/organization/org-left-sidebar.html:9
msgid "Members" msgid "Members"
@ -4885,6 +4903,14 @@ msgstr "Chấp thuận"
msgid "Rejected" msgid "Rejected"
msgstr "Từ chối" msgstr "Từ chối"
#: templates/organization/search-form.html:2
msgid "Organization search"
msgstr "Tìm kiếm nhóm"
#: templates/organization/search-form.html:6
msgid "Search organizations..."
msgstr "Tìm kiếm nhóm"
#: templates/organization/users-table.html:15 #: templates/organization/users-table.html:15
msgid "Kick" msgid "Kick"
msgstr "Đuổi" msgstr "Đuổi"
@ -5678,11 +5704,6 @@ msgstr "Bạn bị ngắt kết nối. Hãy làm mới để xem cập nhật m
msgid "Total:" msgid "Total:"
msgstr "Tổng:" msgstr "Tổng:"
#: templates/submission/list.html:382
#: templates/submission/submission-list-tabs.html:6
msgid "Mine"
msgstr "Tôi"
#: templates/submission/list.html:385 #: templates/submission/list.html:385
#: templates/submission/submission-list-tabs.html:9 #: templates/submission/submission-list-tabs.html:9
msgid "Best" msgid "Best"
@ -6051,11 +6072,6 @@ msgstr "File người dùng"
msgid "Sample" msgid "Sample"
msgstr "" msgstr ""
#: templates/user/import/index.html:105 templates/user/user-left-sidebar.html:6
#: templates/user/user-list-tabs.html:8
msgid "Import"
msgstr ""
#: templates/user/import/table_csv.html:9 #: templates/user/import/table_csv.html:9
msgid "Organizations" msgid "Organizations"
msgstr "Tổ chức" msgstr "Tổ chức"
@ -6241,6 +6257,15 @@ msgstr "Thông tin"
msgid "Check all" msgid "Check all"
msgstr "Chọn tất cả" msgstr "Chọn tất cả"
#~ msgid "My groups"
#~ msgstr "Nhóm của tôi"
#~ msgid "Open groups"
#~ msgstr "Nhóm mở"
#~ msgid "Private groups"
#~ msgstr "Nhóm kín"
#~ msgid "Send message" #~ msgid "Send message"
#~ msgstr "Nhắn tin" #~ msgstr "Nhắn tin"
@ -6526,9 +6551,6 @@ msgstr "Chọn tất cả"
#~ msgid "Frozen" #~ msgid "Frozen"
#~ msgstr "Đã đóng băng" #~ msgstr "Đã đóng băng"
#~ msgid "Show organizations"
#~ msgstr "Hiển thị tổ chức"
#~ msgid "Dislike" #~ msgid "Dislike"
#~ msgstr "Không thích" #~ msgstr "Không thích"
@ -6620,9 +6642,6 @@ msgstr "Chọn tất cả"
#~ msgid "New private contests" #~ msgid "New private contests"
#~ msgstr "Kỳ thi riêng tư mới" #~ msgstr "Kỳ thi riêng tư mới"
#~ msgid "View all"
#~ msgstr "Tất cả"
#~ msgid "New private problems" #~ msgid "New private problems"
#~ msgstr "Bài tập riêng tư mới" #~ msgstr "Bài tập riêng tư mới"

View file

@ -24,9 +24,6 @@ msgstr "Giới thiệu"
msgid "Status" msgid "Status"
msgstr "Máy chấm" msgstr "Máy chấm"
msgid "Courses"
msgstr "Khóa học"
msgid "Suggestions" msgid "Suggestions"
msgstr "Đề xuất ý tưởng" msgstr "Đề xuất ý tưởng"
@ -42,9 +39,6 @@ msgstr "Đăng ký tên"
msgid "Report" msgid "Report"
msgstr "Báo cáo tiêu cực" msgstr "Báo cáo tiêu cực"
msgid "Bug Report"
msgstr "Báo cáo lỗi"
msgid "2sat" msgid "2sat"
msgstr "" msgstr ""
@ -600,6 +594,12 @@ msgstr ""
msgid "z-function" msgid "z-function"
msgstr "" msgstr ""
#~ msgid "Courses"
#~ msgstr "Khóa học"
#~ msgid "Bug Report"
#~ msgstr "Báo cáo lỗi"
#~ msgid "Insert Image" #~ msgid "Insert Image"
#~ msgstr "Chèn hình ảnh" #~ msgstr "Chèn hình ảnh"

View file

@ -791,6 +791,10 @@ noscript #noscript {
background-color: bisque; background-color: bisque;
} }
.background-royalblue {
background-color: royalblue !important;
}
.background-footer { .background-footer {
color: #808080; color: #808080;
} }

View file

@ -134,7 +134,6 @@
border-bottom: 1.4px solid lightgray; border-bottom: 1.4px solid lightgray;
border-top: 1.4px solid lightgray; border-top: 1.4px solid lightgray;
margin-bottom: 1.5em; margin-bottom: 1.5em;
width: 90%;
padding: 1em 1.25em 0.5em 1.25em; padding: 1em 1.25em 0.5em 1.25em;
background-color: white; background-color: white;
margin-left: auto; margin-left: auto;
@ -275,6 +274,7 @@
.right-sidebar { .right-sidebar {
width: 100%; width: 100%;
margin-left: auto; margin-left: auto;
margin-top: 2em;
} }
.actionbar-box { .actionbar-box {
@ -342,6 +342,7 @@
.blog-sidebar, .blog-sidebar,
.right-sidebar { .right-sidebar {
flex: 25%; flex: 25%;
max-width: 25%;
} }
.middle-content { .middle-content {

View file

@ -385,6 +385,47 @@ function activateBlogBoxOnClick() {
}); });
} }
function changeTabParameter(newTab) {
const url = new URL(window.location);
const searchParams = new URLSearchParams(url.search);
searchParams.set('tab', newTab);
searchParams.delete('page');
url.search = searchParams.toString();
return url.href;
}
function submitFormWithParams($form, method) {
const currentUrl = new URL(window.location.href);
const searchParams = new URLSearchParams(currentUrl.search);
const formData = $form.serialize();
const params = new URLSearchParams(formData);
if (searchParams.has('tab')) {
params.set('tab', searchParams.get('tab'));
}
const fullUrl = currentUrl.pathname + '?' + params.toString();
if (method === "GET") {
window.location.href = fullUrl;
}
else {
var $formToSubmit = $('<form>')
.attr('action', fullUrl)
.attr('method', 'POST')
.appendTo('body');
$formToSubmit.append($('<input>').attr({
type: 'hidden',
name: 'csrfmiddlewaretoken',
value: $.cookie('csrftoken')
}));
$formToSubmit.submit();
}
}
function onWindowReady() { function onWindowReady() {
// http://stackoverflow.com/a/1060034/1090657 // http://stackoverflow.com/a/1060034/1090657
var hidden = 'hidden'; var hidden = 'hidden';

View file

@ -1766,6 +1766,9 @@ noscript #noscript {
.background-bisque { .background-bisque {
background-color: rgb(86, 47, 0); background-color: rgb(86, 47, 0);
} }
.background-royalblue {
background-color: rgb(25, 58, 158) !important;
}
.background-footer { .background-footer {
color: rgb(152, 143, 129); color: rgb(152, 143, 129);
} }
@ -2769,6 +2772,10 @@ ul.errorlist {
color: rgb(209, 205, 199); color: rgb(209, 205, 199);
text-decoration-color: initial; text-decoration-color: initial;
} }
.link-row a {
color: inherit;
text-decoration-color: initial;
}
.link-row:hover { .link-row:hover {
background-color: rgb(31, 31, 17); background-color: rgb(31, 31, 17);
color: rgb(249, 146, 97); color: rgb(249, 146, 97);
@ -3171,6 +3178,19 @@ a.voted {
background-image: initial; background-image: initial;
color: rgb(232, 230, 227); color: rgb(232, 230, 227);
} }
.organization-card {
background-color: rgb(24, 26, 27);
border-color: rgb(58, 62, 65);
box-shadow: rgba(0, 0, 0, 0.1) 0px 2px 4px;
color: inherit;
text-decoration-color: initial;
}
.organization-card:hover {
color: rgb(249, 146, 97);
}
.organization-card img.org-logo {
background-color: rgb(32, 35, 37);
}
.organization-row { .organization-row {
border-bottom-color: rgb(62, 68, 70); border-bottom-color: rgb(62, 68, 70);
border-top: none; border-top: none;
@ -3179,16 +3199,13 @@ a.voted {
.organization-row:hover { .organization-row:hover {
background-color: rgb(31, 33, 35); background-color: rgb(31, 33, 35);
} }
.organization-container {
border-color: rgb(62, 68, 70);
}
.org-help-text { .org-help-text {
color: rgb(152, 143, 129); color: rgb(152, 143, 129);
} }
.ticket-container #content > h2:first-child small { .ticket-container #content > h2:first-child small {
color: rgb(168, 160, 149); color: rgb(168, 160, 149);
} }
.ticket-container #content > h2:first-child .fa-check-circle-o { .ticket-container #content > h2:first-child .fa-check-circle {
color: rgb(86, 255, 86); color: rgb(86, 255, 86);
} }
.ticket-container #content > h2:first-child .fa-exclamation-circle { .ticket-container #content > h2:first-child .fa-exclamation-circle {

View file

@ -1,3 +1,5 @@
@import "vars";
.leave-organization, .leave-organization:hover { .leave-organization, .leave-organization:hover {
color: red; color: red;
} }
@ -28,6 +30,79 @@
display: contents; display: contents;
} }
.organization-container {
display: flex;
flex-wrap: wrap;
gap: 1em;
justify-content: flex-start;
width: 100%;
box-sizing: border-box;
margin-bottom: 1em;
}
.organization-card {
background-color: #fff;
border: 1px solid #ddd;
border-radius: 8px;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
text-align: center;
padding: 1em;
transition: transform 0.3s;
box-sizing: border-box;
display: flex;
flex-direction: column;
justify-content: space-between;
height: 300px;
margin-bottom: 1em;
text-decoration: none;
color: inherit;
&:hover {
transform: translateY(-5px);
color: $theme_color;
}
img.org-logo {
width: 100%;
border-radius: 8px 8px 0 0;
object-fit: contain;
object-position: center;
flex-shrink: 0;
background-color: #f0f0f0;
}
.org-details {
padding: 1em 0;
span {
display: block;
margin-bottom: 0.5em;
}
}
}
@media(min-width: 800px) {
.organization-card {
flex: 1 1 calc(33.33% - 1em);
max-width: calc(33.33% - 1em);
img.org-logo {
height: 150px;
}
}
}
@media(max-width: 799px) {
.organization-card {
flex: 1 1 calc(50% - 1em);
max-width: calc(50% - 1em);
img.org-logo {
height: 120px;
}
}
}
.organization-row { .organization-row {
display: block; display: block;
padding: 0.5em; padding: 0.5em;
@ -37,19 +112,18 @@
font-weight: 500; font-weight: 500;
display: flex; display: flex;
align-items: center; align-items: center;
}
.organization-row:hover { &:hover {
background-color: #f3f3f3; background-color: #f3f3f3;
} }
.organization-container {
border: 1px #ccc solid;
margin-bottom: 3em;
border-radius: 5px;
} }
.org-help-text { .org-help-text {
display: block; display: block;
color: gray; color: gray;
} }
#search-organization {
width: 100%;
height: 2.3em;
}

View file

@ -10,7 +10,7 @@
display: inline; display: inline;
} }
#content > h2:first-child .fa-check-circle-o { #content > h2:first-child .fa-check-circle {
color: #00a900; color: #00a900;
} }

View file

@ -33,47 +33,6 @@
{% block three_col_js %} {% block three_col_js %}
<script type="text/javascript"> <script type="text/javascript">
function changeTabParameter(newTab) {
const url = new URL(window.location);
const searchParams = new URLSearchParams(url.search);
searchParams.set('tab', newTab);
searchParams.delete('page');
url.search = searchParams.toString();
return url.href;
}
function submitFormWithParams($form, method) {
const currentUrl = new URL(window.location.href);
const searchParams = new URLSearchParams(currentUrl.search);
const formData = $form.serialize();
const params = new URLSearchParams(formData);
if (searchParams.has('tab')) {
params.set('tab', searchParams.get('tab'));
}
const fullUrl = currentUrl.pathname + '?' + params.toString();
if (method === "GET") {
window.location.href = fullUrl;
}
else {
var $formToSubmit = $('<form>')
.attr('action', fullUrl)
.attr('method', 'POST')
.appendTo('body');
$formToSubmit.append($('<input>').attr({
type: 'hidden',
name: 'csrfmiddlewaretoken',
value: $.cookie('csrftoken')
}));
$formToSubmit.submit();
}
}
$(document).ready(function () { $(document).ready(function () {
$('#active-url').attr('href', changeTabParameter('active')); $('#active-url').attr('href', changeTabParameter('active'));
$('#current-url').attr('href', changeTabParameter('current')); $('#current-url').attr('href', changeTabParameter('current'));

View file

@ -2,7 +2,7 @@
{{ make_tab_item('home', 'fa fa-home', course.get_absolute_url(), _('Home')) }} {{ make_tab_item('home', 'fa fa-home', course.get_absolute_url(), _('Home')) }}
{% if is_editable %} {% if is_editable %}
{{ make_tab_item('edit_lesson', 'fa fa-edit', url('edit_course_lessons', course.slug), _('Edit lessons')) }} {{ make_tab_item('edit_lesson', 'fa fa-edit', url('edit_course_lessons', course.slug), _('Edit lessons')) }}
{{ make_tab_item('grades', 'fa fa-check-square-o', url('course_grades', course.slug), _('Grades')) }} {{ make_tab_item('grades', 'fa fa-check-square', url('course_grades', course.slug), _('Grades')) }}
{% endif %} {% endif %}
{% if perms.judge.change_course %} {% if perms.judge.change_course %}
{{ make_tab_item('admin', 'fa fa-edit', url('admin:judge_course_change', course.id), _('Admin'), force_new_page=True) }} {{ make_tab_item('admin', 'fa fa-edit', url('admin:judge_course_change', course.id), _('Admin'), force_new_page=True) }}

View file

@ -1,50 +1,110 @@
{% extends "two-column-content.html" %} {% extends "three-column-content.html" %}
{% block two_col_media %} {% block three_col_js %}
<style> <script type="text/javascript">
.organization-container { $(document).ready(function () {
border-bottom: none; $('#mine-tab').attr('href', changeTabParameter('mine'));
} $('#public-tab').attr('href', changeTabParameter('public'));
.org-logo { $('#private-tab').attr('href', changeTabParameter('private'));
height: 2em;
width: 2em; var $form = $('form#filter-form');
margin-right: 1em;
margin-left: 0.5em; $('#go').click(function() {
} submitFormWithParams($form, "GET");
.toggle { });
cursor: pointer;
} $form.on('keypress', function(e) {
</style> if (e.key === 'Enter') {
e.preventDefault();
}
});
$('#search-organization').keypress(function (e) {
if (e.keyCode === 13) {
$('#go').click();
}
});
$('#order').select2();
});
</script>
{% block contest_list_js %}{% endblock %}
{% endblock %} {% endblock %}
{% block title_ruler %}{% endblock %}
{% block left_sidebar %} {% block left_sidebar %}
{% include "user/user-left-sidebar.html" %} <div class="left-sidebar">
{% if request.user.is_authenticated %}
{{ make_tab_item('mine', 'fa fa-user', request.path + '?tab=mine', _('Mine')) }}
{% endif %}
{{ make_tab_item('public', 'fa fa-globe', request.path + '?tab=public', _('Public')) }}
{{ make_tab_item('private', 'fa fa-lock', request.path + '?tab=private', _('Private')) }}
{% if request.user.is_superuser %}
{{ make_tab_item('import', 'fa fa-table', url('import_users'), _('Import'), force_new_page=True) }}
{% endif %}
</div>
{% endblock %} {% endblock %}
{% macro org_list(title, queryset) %} {% block right_sidebar %}
<div class="right-sidebar">
{% include "organization/search-form.html" %}
</div>
{% endblock %}
{% macro org_list(queryset, tab) %}
{% if queryset %} {% if queryset %}
<h3 style="padding-bottom: 1em" class="toggle open"><i class="fa fa-chevron-right fa-fw"></i> {{title}} ({{queryset.count()}})</h3> <div class="organization-container">
<div class="organization-container toggled">
{% for org in queryset %} {% for org in queryset %}
<a href="{{ org.get_absolute_url() }}" class="organization-row"> <div class="organization-card" style="cursor: pointer;" onclick="location.href='{{ org.get_absolute_url() }}';">
{% if org.logo_override_image %} {% if org.logo_override_image %}
<img class="user-img org-logo" loading="lazy" src="{{ org.logo_override_image }}"> <img class="org-logo" loading="lazy" src="{{ org.logo_override_image }}">
{% else %} {% else %}
<img class="org-logo" loading="lazy" src="{{ static('icons/icon.svg') }}" onerror="{{static('icons/logo.svg')}}"> <img class="org-logo" loading="lazy" src="{{ static('icons/icon.svg') }}" onerror="this.onerror=null;this.src='{{ static('icons/logo.svg') }}';">
{% endif %} {% endif %}
<span style="margin-right: auto">{{ org.name }}</span> <div class="org-details">
<span style="font-weight: normal"><i>{{ org.member_count }} {{_('members')}}</i></span> <span style="font-weight: bold;">{{ org.name }}</span>
</a> <span style="margin-bottom: 0"><i>{{ org.member_count }} {{ _('members') }}</i></span>
</div>
{% if tab == 'mine' %}
<div class="background-royalblue button small">{{ _('View') }}</div>
{% elif tab == 'public' %}
<form method="post" action="{{ url('join_organization', org.id, org.slug) }}">
{% csrf_token %}
<input type="submit" style="width: 100%" class="background-royalblue button small" value="{{ _('Join') }}">
</form>
{% else %}
<a href="{{ url('request_organization', org.id, org.slug) }}" style="font-size: 15px;" class="background-royalblue button small">{{ _('Request membership') }}</a>
{% endif %}
</div>
{% endfor %} {% endfor %}
</div> </div>
{% if page_obj and page_obj.num_pages > 1 %}
{% include "list-pages.html" %}
{% endif %}
{% endif %} {% endif %}
{% endmacro %} {% endmacro %}
{% block middle_content %} {% block middle_content %}
<a style="float: right" class="button small" href="{{url('organization_add')}}">{{_("Create group")}}</a> {% if current_tab == 'mine' %}
{{ org_list(_('My groups'), my_organizations) }} {% if organizations %}
{{ org_list(_('Open groups'), open_organizations) }} {{ org_list(organizations, 'mine') }}
{{ org_list(_('Private groups'), private_organizations) }} {% else %}
{% endblock %} <i> {{ _('You have not joined any organization yet.') }} </i>
{% endif %}
{% endif %}
{% if current_tab == 'public' %}
{% if organizations %}
{{ org_list(organizations, 'public') }}
{% else %}
<i> {{ _('There is no public organization.') }} </i>
{% endif %}
{% endif %}
{% if current_tab == 'private' %}
{% if organizations %}
{{ org_list(organizations, 'private') }}
{% else %}
<i> {{ _('There is no private organization.') }} </i>
{% endif %}
{% endif %}
{% endblock %}

View file

@ -0,0 +1,24 @@
<div class="sidebox">
<h3 class="colored-text"><i class="fa fa-search"></i>{{ _('Organization search') }}</h3>
<div class="sidebox-content">
<form id="filter-form" method="GET">
<input id="search-organization" type="text" name="organization" value="{{ organization_query or '' }}"
placeholder="{{ _('Search organizations...') }}">
<div class="filter-form-group">
<label for="order" class="bold-text margin-label">{{ _('Order by') }}</label>
<select id="order" name="order" style="width: 100%">
<option value="">---</option>
{% for value, name in all_sort_options %}
<option value="{{value}}"{% if selected_order == value%} selected{% endif %}>
{{ name }}
</option>
{% endfor %}
</select>
</div>
<div class="form-submit-group">
<a class="button small" href="{{url('organization_add')}}">{{_("Create group")}}</a>
<a id="go" class="button small">{{ _('Go') }}</a>
</div>
</form>
</div>
</div>

View file

@ -7,7 +7,7 @@
{% endblock %} {% endblock %}
{% block middle_content %} {% block middle_content %}
<div class="tabs tabs-no-flex" style="width: 90%;margin-left: auto;margin-right: auto;"> <div class="tabs tabs-no-flex">
<ul> <ul>
<li class="{{'active' if feed_type=='for_you'}}"> <li class="{{'active' if feed_type=='for_you'}}">
<a href="{{url('problem_feed')}}">{{_('FOR YOU')}}</a> <a href="{{url('problem_feed')}}">{{_('FOR YOU')}}</a>

View file

@ -58,7 +58,7 @@
{% if not hide_contest_in_row and submission.contest_object_id %} {% if not hide_contest_in_row and submission.contest_object_id %}
<a href="{{ url('contest_view', submission.contest_object.key) }}" <a href="{{ url('contest_view', submission.contest_object.key) }}"
class="submission-contest"> class="submission-contest">
<i title="{{ submission.contest_object.name }}" class="fa fa-dot-circle-o"></i> <i title="{{ submission.contest_object.name }}" class="far fa-dot-circle"></i>
</a> </a>
{% endif %} {% endif %}
</div> </div>

View file

@ -1,7 +1,7 @@
{% extends "base.html" %} {% extends "base.html" %}
{% block media %} {% block media %}
<style> <style>
#ticket-list .fa-check-circle-o { #ticket-list .fa-check-circle {
color: #00a900; color: #00a900;
} }
@ -131,10 +131,10 @@
if ($row.length) { if ($row.length) {
var $status = $row.find('td').first().find('i'); var $status = $row.find('td').first().find('i');
if (ticket.open) { if (ticket.open) {
$status.removeClass('fa-check-circle-o').addClass('fa-exclamation-circle'); $status.removeClass('fa-check-circle').addClass('fa-exclamation-circle');
notify('ticket', '{{ _('Reopened: ') }}' + ticket.title); notify('ticket', '{{ _('Reopened: ') }}' + ticket.title);
} else { } else {
$status.removeClass('fa-exclamation-circle').addClass('fa-check-circle-o'); $status.removeClass('fa-exclamation-circle').addClass('fa-check-circle');
notify('ticket', '{{ _('Closed: ') }}' + ticket.title); notify('ticket', '{{ _('Closed: ') }}' + ticket.title);
} }
} }

View file

@ -1,5 +1,5 @@
<tr id="ticket-{{ ticket.id }}"> <tr id="ticket-{{ ticket.id }}">
<td><i class="fa {% if ticket.is_open %}fa-exclamation-circle{% else %}fa-check-circle-o{% endif %}"></i></td> <td><i class="fa {% if ticket.is_open %}fa-exclamation-circle{% else %}fa-check-circle{% endif %}"></i></td>
<td>{{ ticket.id }}</td> <td>{{ ticket.id }}</td>
<td><a href="{{ url('ticket', ticket.id) }}">{{ ticket.title }}</a></td> <td><a href="{{ url('ticket', ticket.id) }}">{{ ticket.title }}</a></td>
<td>{{ link_user(ticket.user) }}</td> <td>{{ link_user(ticket.user) }}</td>

View file

@ -13,9 +13,9 @@
function update_ticket_state(open) { function update_ticket_state(open) {
if (open) if (open)
$status.removeClass('fa-check-circle-o').addClass('fa-exclamation-circle'); $status.removeClass('fa-check-circle').addClass('fa-exclamation-circle');
else else
$status.removeClass('fa-exclamation-circle').addClass('fa-check-circle-o'); $status.removeClass('fa-exclamation-circle').addClass('fa-check-circle');
$('.close-ticket').toggle(open); $('.close-ticket').toggle(open);
$('.open-ticket').toggle(!open); $('.open-ticket').toggle(!open);
} }
@ -144,7 +144,7 @@
{% block content_title %} {% block content_title %}
<span class="status"> <span class="status">
<i class="fa {% if ticket.is_open %}fa-exclamation-circle{% else %}fa-check-circle-o{% endif %}"></i> <i class="fa {% if ticket.is_open %}fa-exclamation-circle{% else %}fa-check-circle{% endif %}"></i>
</span> </span>
<span class="title">{{ ticket.title }}</span><small>#{{ ticket.id }}</small> <span class="title">{{ ticket.title }}</span><small>#{{ ticket.id }}</small>
{% endblock %} {% endblock %}