Improve notif and organization add member

This commit is contained in:
cuom1999 2024-08-13 17:42:51 +07:00
parent cdbed121cd
commit 7406d081aa
10 changed files with 297 additions and 149 deletions

View file

@ -369,7 +369,7 @@ class AddOrganizationMemberForm(ModelForm):
label=_("New users"), label=_("New users"),
) )
def clean(self): def clean_new_users(self):
new_users = self.cleaned_data.get("new_users") or "" new_users = self.cleaned_data.get("new_users") or ""
usernames = new_users.split() usernames = new_users.split()
invalid_usernames = [] invalid_usernames = []
@ -387,8 +387,7 @@ class AddOrganizationMemberForm(ModelForm):
usernames=str(invalid_usernames) usernames=str(invalid_usernames)
) )
) )
self.cleaned_data["new_users"] = valid_usernames return valid_usernames
return self.cleaned_data
class Meta: class Meta:
model = Organization model = Organization

View file

@ -0,0 +1,21 @@
# Generated by Django 3.2.18 on 2024-08-13 10:36
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("judge", "0189_organization_image"),
]
operations = [
migrations.RemoveField(
model_name="notification",
name="comment",
),
migrations.RemoveField(
model_name="notification",
name="read",
),
]

View file

@ -7,6 +7,20 @@ from judge.models import Profile, Comment
from judge.caching import cache_wrapper from judge.caching import cache_wrapper
category_to_verbose_message = {
"Add blog": _("Added a post"),
"Added to group": _("You are added to a group"),
"Comment": _("You have a new comment"),
"Delete blog": _("Deleted a post"),
"Reject blog": _("Rejected a post"),
"Approve blog": _("Approved a post"),
"Edit blog": _("Edited a post"),
"Mention": _("Mentioned you"),
"Reply": _("Replied you"),
"Ticket": _("Ticket"),
}
class Notification(models.Model): class Notification(models.Model):
owner = models.ForeignKey( owner = models.ForeignKey(
Profile, Profile,
@ -27,10 +41,29 @@ class Notification(models.Model):
verbose_name=_("who trigger, used for non-comment"), verbose_name=_("who trigger, used for non-comment"),
on_delete=CASCADE, on_delete=CASCADE,
) )
comment = models.ForeignKey(
Comment, null=True, verbose_name=_("comment"), on_delete=CASCADE def verbose_activity(self):
) # deprecated if self.category in category_to_verbose_message:
read = models.BooleanField(verbose_name=_("read"), default=False) # deprecated return category_to_verbose_message[self.category]
if "Problem public" in self.category:
is_public = "True" in self.category
if "(" in self.category and ")" in self.category:
groups = self.category.split("(", 1)[1].strip(")")
if is_public:
verbose_message = _("The problem is public to: ") + groups
else:
verbose_message = _("The problem is private to: ") + groups
else:
verbose_message = (
_("The problem is public to everyone.")
if is_public
else _("The problem is private.")
)
return verbose_message
return self.category
class NotificationProfile(models.Model): class NotificationProfile(models.Model):

View file

@ -158,7 +158,11 @@ class Organization(models.Model):
return reverse("organization_submissions", args=(self.id, self.slug)) return reverse("organization_submissions", args=(self.id, self.slug))
def is_admin(self, profile): def is_admin(self, profile):
return self.admins.filter(id=profile.id).exists() return profile.id in self.get_admin_ids()
@cache_wrapper(prefix="Orgai", expected_type=list)
def get_admin_ids(self):
return list(self.admins.values_list("id", flat=True))
def is_member(self, profile): def is_member(self, profile):
return profile in self return profile in self

View file

@ -142,6 +142,7 @@ def contest_submission_delete(sender, instance, **kwargs):
@receiver(post_save, sender=Organization) @receiver(post_save, sender=Organization)
def organization_update(sender, instance, **kwargs): def organization_update(sender, instance, **kwargs):
cache.delete_many([make_template_fragment_key("organization_html", (instance.id,))]) cache.delete_many([make_template_fragment_key("organization_html", (instance.id,))])
Organization.get_admin_ids.dirty(instance)
_misc_config_i18n = [code for code, _ in settings.LANGUAGES] _misc_config_i18n = [code for code, _ in settings.LANGUAGES]

View file

@ -793,8 +793,12 @@ class AddOrganizationMember(
def form_valid(self, form): def form_valid(self, form):
new_users = form.cleaned_data["new_users"] new_users = form.cleaned_data["new_users"]
self.object.members.add(*new_users) self.object.members.add(*new_users)
link = reverse("organization_home", args=[self.object.id, self.object.slug])
html = f'<a href="{link}">{self.object.name}</a>'
make_notification(new_users, "Added to group", html, self.request.profile)
with revisions.create_revision(): with revisions.create_revision():
revisions.set_comment(_("Added members from site")) usernames = ", ".join([u.username for u in new_users])
revisions.set_comment(_("Added members from site") + ": " + usernames)
revisions.set_user(self.request.user) revisions.set_user(self.request.user)
return super(AddOrganizationMember, self).form_valid(form) return super(AddOrganizationMember, self).form_valid(form)
@ -819,7 +823,7 @@ class KickUserWidgetView(
status=400, status=400,
) )
if not organization.members.filter(id=user.id).exists(): if not organization.is_member(user):
return generic_message( return generic_message(
request, request,
_("Can't kick user"), _("Can't kick user"),
@ -828,7 +832,20 @@ class KickUserWidgetView(
status=400, status=400,
) )
if organization.is_admin(user):
return generic_message(
request,
_("Can't kick user"),
_("The user you are trying to kick is an organization admin."),
status=400,
)
with revisions.create_revision():
revisions.set_comment(_("Kicked member") + " " + user.username)
revisions.set_user(self.request.user)
organization.members.remove(user) organization.members.remove(user)
organization.save()
return HttpResponseRedirect(organization.get_users_url()) return HttpResponseRedirect(organization.get_users_url())

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-07-20 21:06+0700\n" "POT-Creation-Date: 2024-08-13 17:34+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"
@ -25,12 +25,12 @@ msgstr "xem lần cuối"
#: chat_box/models.py:54 chat_box/models.py:79 chat_box/models.py:95 #: chat_box/models.py:54 chat_box/models.py:79 chat_box/models.py:95
#: judge/admin/interface.py:151 judge/models/contest.py:693 #: judge/admin/interface.py:151 judge/models/contest.py:693
#: judge/models/contest.py:899 judge/models/course.py:129 #: judge/models/contest.py:899 judge/models/course.py:129
#: judge/models/profile.py:473 judge/models/profile.py:547 #: judge/models/profile.py:475 judge/models/profile.py:549
msgid "user" msgid "user"
msgstr "người dùng" msgstr "người dùng"
#: chat_box/models.py:56 judge/models/comment.py:45 #: chat_box/models.py:56 judge/models/comment.py:45
#: judge/models/notification.py:17 #: judge/models/notification.py:31
msgid "posted time" msgid "posted time"
msgstr "thời gian đăng" msgstr "thời gian đăng"
@ -46,12 +46,13 @@ msgstr ""
msgid "Recent" msgid "Recent"
msgstr "Gần đây" msgstr "Gần đây"
#: chat_box/views.py:448 templates/base.html:199 #: chat_box/views.py:448 templates/base.html:198
#: 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
#: templates/internal/problem/problem.html:63 #: templates/internal/problem/problem.html:63
#: templates/organization/org-left-sidebar.html:12 #: templates/organization/org-left-sidebar.html:12
#: templates/organization/users-table.html:19
#: templates/problem/left-sidebar.html:6 #: templates/problem/left-sidebar.html:6
#: templates/problem/problem-list-tabs.html:6 #: templates/problem/problem-list-tabs.html:6
#: templates/submission/info-base.html:12 templates/submission/list.html:394 #: templates/submission/info-base.html:12 templates/submission/list.html:394
@ -87,7 +88,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:121 #: dmoj/urls.py:221 templates/base.html:120
#: 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 +127,7 @@ msgstr ""
msgid "Problem" msgid "Problem"
msgstr "Bài tập" msgstr "Bài tập"
#: judge/admin/contest.py:183 templates/base.html:214 #: judge/admin/contest.py:183 templates/base.html:213
#: templates/user/user-tabs.html:12 #: templates/user/user-tabs.html:12
msgid "Settings" msgid "Settings"
msgstr "Cài đặt" msgstr "Cài đặt"
@ -198,7 +199,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:254 #: judge/admin/contest.py:540 templates/base.html:253
msgid "virtual" msgid "virtual"
msgstr "ảo" msgstr "ảo"
@ -268,7 +269,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:165 templates/stats/tab.html:4 #: templates/base.html:164 templates/stats/tab.html:4
#: templates/submission/list.html:345 #: templates/submission/list.html:345
msgid "Language" msgid "Language"
msgstr "Ngôn ngữ" msgstr "Ngôn ngữ"
@ -557,55 +558,55 @@ msgstr "Thành viên mới"
msgid "These usernames don't exist: {usernames}" msgid "These usernames don't exist: {usernames}"
msgstr "Các tên đăng nhập này không tồn tại: {usernames}" msgstr "Các tên đăng nhập này không tồn tại: {usernames}"
#: judge/forms.py:446 #: judge/forms.py:445
msgid "Username/Email" msgid "Username/Email"
msgstr "Tên đăng nhập / Email" msgstr "Tên đăng nhập / Email"
#: judge/forms.py:448 judge/views/email.py:22 #: judge/forms.py:447 judge/views/email.py:22
#: templates/registration/registration_form.html:46 #: templates/registration/registration_form.html:46
#: templates/registration/registration_form.html:60 #: templates/registration/registration_form.html:60
#: templates/user/edit-profile.html:115 templates/user/import/table_csv.html:5 #: templates/user/edit-profile.html:115 templates/user/import/table_csv.html:5
msgid "Password" msgid "Password"
msgstr "Mật khẩu" msgstr "Mật khẩu"
#: judge/forms.py:474 #: judge/forms.py:473
msgid "Two Factor Authentication tokens must be 6 decimal digits." msgid "Two Factor Authentication tokens must be 6 decimal digits."
msgstr "Two Factor Authentication phải chứa 6 chữ số." msgstr "Two Factor Authentication phải chứa 6 chữ số."
#: judge/forms.py:487 templates/registration/totp_auth.html:32 #: judge/forms.py:486 templates/registration/totp_auth.html:32
msgid "Invalid Two Factor Authentication token." msgid "Invalid Two Factor Authentication token."
msgstr "Token Two Factor Authentication không hợp lệ." msgstr "Token Two Factor Authentication không hợp lệ."
#: judge/forms.py:494 judge/models/problem.py:133 #: judge/forms.py:493 judge/models/problem.py:133
msgid "Problem code must be ^[a-z0-9]+$" msgid "Problem code must be ^[a-z0-9]+$"
msgstr "Mã bài phải có dạng ^[a-z0-9]+$" msgstr "Mã bài phải có dạng ^[a-z0-9]+$"
#: judge/forms.py:501 #: judge/forms.py:500
msgid "Problem with code already exists." msgid "Problem with code already exists."
msgstr "Mã bài đã tồn tại." msgstr "Mã bài đã tồn tại."
#: judge/forms.py:508 judge/models/contest.py:102 #: judge/forms.py:507 judge/models/contest.py:102
msgid "Contest id must be ^[a-z0-9]+$" msgid "Contest id must be ^[a-z0-9]+$"
msgstr "Mã kỳ thi phải có dạng ^[a-z0-9]+$" msgstr "Mã kỳ thi phải có dạng ^[a-z0-9]+$"
#: judge/forms.py:515 templates/contest/clone.html:47 #: judge/forms.py:514 templates/contest/clone.html:47
#: templates/contest/search-form.html:12 templates/problem/search-form.html:39 #: templates/contest/search-form.html:12 templates/problem/search-form.html:39
msgid "Group" msgid "Group"
msgstr "Nhóm" msgstr "Nhóm"
#: judge/forms.py:523 #: judge/forms.py:522
msgid "Contest with key already exists." msgid "Contest with key already exists."
msgstr "Mã kỳ thi đã tồn tại." msgstr "Mã kỳ thi đã tồn tại."
#: judge/forms.py:531 #: judge/forms.py:530
msgid "Group doesn't exist." msgid "Group doesn't exist."
msgstr "Nhóm không tồn tại." msgstr "Nhóm không tồn tại."
#: judge/forms.py:533 #: judge/forms.py:532
msgid "You don't have permission in this group." msgid "You don't have permission in this group."
msgstr "Bạn không có quyền trong nhóm này." msgstr "Bạn không có quyền trong nhóm này."
#: judge/forms.py:583 #: judge/forms.py:582
msgid "This problem is duplicated." msgid "This problem is duplicated."
msgstr "Bài này bị lặp" msgstr "Bài này bị lặp"
@ -670,7 +671,7 @@ msgstr "ẩn bình luận"
msgid "parent" msgid "parent"
msgstr "" msgstr ""
#: judge/models/comment.py:65 judge/models/notification.py:31 #: judge/models/comment.py:65
msgid "comment" msgid "comment"
msgstr "bình luận" msgstr "bình luận"
@ -925,7 +926,7 @@ msgstr "riêng tư với các tổ chức"
#: judge/models/contest.py:245 judge/models/course.py:33 #: judge/models/contest.py:245 judge/models/course.py:33
#: judge/models/interface.py:93 judge/models/problem.py:281 #: judge/models/interface.py:93 judge/models/problem.py:281
#: judge/models/profile.py:175 #: judge/models/profile.py:177
msgid "organizations" msgid "organizations"
msgstr "tổ chức" msgstr "tổ chức"
@ -1465,7 +1466,7 @@ msgstr "người nhận"
msgid "message timestamp" msgid "message timestamp"
msgstr "thời gian gửi" msgstr "thời gian gửi"
#: judge/models/message.py:28 judge/models/notification.py:33 #: judge/models/message.py:28
msgid "read" msgid "read"
msgstr "" msgstr ""
@ -1473,22 +1474,78 @@ msgstr ""
msgid "messages in the thread" msgid "messages in the thread"
msgstr "tin nhắn trong chuỗi" msgstr "tin nhắn trong chuỗi"
#: judge/models/notification.py:11
msgid "Added a post"
msgstr "Thêm bài đăng"
#: judge/models/notification.py:12
msgid "You are added to a group"
msgstr "Bạn đã được thêm vào nhóm."
#: judge/models/notification.py:13 #: judge/models/notification.py:13
msgid "You have a new comment"
msgstr "Bạn có bình luận mới"
#: judge/models/notification.py:14
msgid "Deleted a post"
msgstr "Đã xóa bài đăng"
#: judge/models/notification.py:15
msgid "Rejected a post"
msgstr "Đã từ chối bài đăng"
#: judge/models/notification.py:16
msgid "Approved a post"
msgstr "Đã chấp thuận bài đăng"
#: judge/models/notification.py:17
msgid "Edited a post"
msgstr "Đã chỉnh sửa bài đăng"
#: judge/models/notification.py:18
msgid "Mentioned you"
msgstr "Đã nhắc đến bạn"
#: judge/models/notification.py:19
msgid "Replied you"
msgstr "Đã phản hồi bạn"
#: judge/models/notification.py:20 templates/blog/list.html:47
msgid "Ticket"
msgstr "Báo cáo"
#: judge/models/notification.py:27
msgid "owner" msgid "owner"
msgstr "" msgstr ""
#: judge/models/notification.py:18 #: judge/models/notification.py:32
msgid "category" msgid "category"
msgstr "" msgstr ""
#: judge/models/notification.py:21 #: judge/models/notification.py:35
msgid "html link to comments, used for non-comments" msgid "html link to comments, used for non-comments"
msgstr "" msgstr ""
#: judge/models/notification.py:27 #: judge/models/notification.py:41
msgid "who trigger, used for non-comment" msgid "who trigger, used for non-comment"
msgstr "" msgstr ""
#: judge/models/notification.py:54
msgid "The problem is public to: "
msgstr "Bài tập được công khai trong: "
#: judge/models/notification.py:56
msgid "The problem is private to: "
msgstr "Bài tập riêng tư trong: "
#: judge/models/notification.py:59
msgid "The problem is public to everyone."
msgstr "Bài tập được công khai với mọi người."
#: judge/models/notification.py:60
msgid "The problem is private."
msgstr "Bài tập được đánh dấu riêng tư."
#: judge/models/pagevote.py:25 #: judge/models/pagevote.py:25
#, fuzzy #, fuzzy
#| msgid "votes" #| msgid "votes"
@ -2047,144 +2104,144 @@ msgid ""
"organization." "organization."
msgstr "Ảnh này sẽ thay thế logo mặc định khi ở trong tổ chức." msgstr "Ảnh này sẽ thay thế logo mặc định khi ở trong tổ chức."
#: judge/models/profile.py:174 judge/models/profile.py:206 #: judge/models/profile.py:176 judge/models/profile.py:208
#: judge/models/profile.py:479 judge/models/profile.py:554 #: judge/models/profile.py:481 judge/models/profile.py:556
msgid "organization" msgid "organization"
msgstr "" msgstr ""
#: judge/models/profile.py:181 #: judge/models/profile.py:183
msgid "user associated" msgid "user associated"
msgstr "" msgstr ""
#: judge/models/profile.py:184 #: judge/models/profile.py:186
msgid "self-description" msgid "self-description"
msgstr "" msgstr ""
#: judge/models/profile.py:188 #: judge/models/profile.py:190
msgid "location" msgid "location"
msgstr "" msgstr ""
#: judge/models/profile.py:194 #: judge/models/profile.py:196
msgid "preferred language" msgid "preferred language"
msgstr "" msgstr ""
#: judge/models/profile.py:202 #: judge/models/profile.py:204
msgid "last access time" msgid "last access time"
msgstr "" msgstr ""
#: judge/models/profile.py:203 #: judge/models/profile.py:205
msgid "last IP" msgid "last IP"
msgstr "" msgstr ""
#: judge/models/profile.py:214 #: judge/models/profile.py:216
msgid "display rank" msgid "display rank"
msgstr "" msgstr ""
#: judge/models/profile.py:223 #: judge/models/profile.py:225
msgid "comment mute" msgid "comment mute"
msgstr "" msgstr ""
#: judge/models/profile.py:224 #: judge/models/profile.py:226
msgid "Some users are at their best when silent." msgid "Some users are at their best when silent."
msgstr "" msgstr ""
#: judge/models/profile.py:228 #: judge/models/profile.py:230
msgid "unlisted user" msgid "unlisted user"
msgstr "" msgstr ""
#: judge/models/profile.py:229 #: judge/models/profile.py:231
msgid "User will not be ranked." msgid "User will not be ranked."
msgstr "" msgstr ""
#: judge/models/profile.py:235 #: judge/models/profile.py:237
msgid "current contest" msgid "current contest"
msgstr "kỳ thi hiện tại" msgstr "kỳ thi hiện tại"
#: judge/models/profile.py:242 #: judge/models/profile.py:244
msgid "2FA enabled" msgid "2FA enabled"
msgstr "" msgstr ""
#: judge/models/profile.py:244 #: judge/models/profile.py:246
msgid "check to enable TOTP-based two factor authentication" msgid "check to enable TOTP-based two factor authentication"
msgstr "đánh dấu để sử dụng TOTP-based two factor authentication" msgstr "đánh dấu để sử dụng TOTP-based two factor authentication"
#: judge/models/profile.py:250 #: judge/models/profile.py:252
msgid "TOTP key" msgid "TOTP key"
msgstr "mã TOTP" msgstr "mã TOTP"
#: judge/models/profile.py:251 #: judge/models/profile.py:253
msgid "32 character base32-encoded key for TOTP" msgid "32 character base32-encoded key for TOTP"
msgstr "" msgstr ""
#: judge/models/profile.py:253 #: judge/models/profile.py:255
msgid "TOTP key must be empty or base32" msgid "TOTP key must be empty or base32"
msgstr "" msgstr ""
#: judge/models/profile.py:257 #: judge/models/profile.py:259
msgid "internal notes" msgid "internal notes"
msgstr "ghi chú nội bộ" msgstr "ghi chú nội bộ"
#: judge/models/profile.py:260 #: judge/models/profile.py:262
msgid "Notes for administrators regarding this user." msgid "Notes for administrators regarding this user."
msgstr "Ghi chú riêng cho quản trị viên." msgstr "Ghi chú riêng cho quản trị viên."
#: judge/models/profile.py:265 #: judge/models/profile.py:267
msgid "Custom background" msgid "Custom background"
msgstr "Background tự chọn" msgstr "Background tự chọn"
#: judge/models/profile.py:268 #: judge/models/profile.py:270
msgid "CSS custom background properties: url(\"image_url\"), color, etc" msgid "CSS custom background properties: url(\"image_url\"), color, etc"
msgstr "CSS background tự chọn. Ví dụ: url(\"image_url\"), white, ..." msgstr "CSS background tự chọn. Ví dụ: url(\"image_url\"), white, ..."
#: judge/models/profile.py:436 #: judge/models/profile.py:438
msgid "user profile" msgid "user profile"
msgstr "thông tin người dùng" msgstr "thông tin người dùng"
#: judge/models/profile.py:437 #: judge/models/profile.py:439
msgid "user profiles" msgid "user profiles"
msgstr "thông tin người dùng" msgstr "thông tin người dùng"
#: judge/models/profile.py:443 #: judge/models/profile.py:445
#, fuzzy #, fuzzy
#| msgid "associated page" #| msgid "associated page"
msgid "profile associated" msgid "profile associated"
msgstr "trang tương ứng" msgstr "trang tương ứng"
#: judge/models/profile.py:450 #: judge/models/profile.py:452
msgid "t-shirt size" msgid "t-shirt size"
msgstr "" msgstr ""
#: judge/models/profile.py:455 #: judge/models/profile.py:457
#, fuzzy #, fuzzy
#| msgid "date of publishing" #| msgid "date of publishing"
msgid "date of birth" msgid "date of birth"
msgstr "Ngày công bố" msgstr "Ngày công bố"
#: judge/models/profile.py:461 #: judge/models/profile.py:463
msgid "address" msgid "address"
msgstr "" msgstr ""
#: judge/models/profile.py:483 #: judge/models/profile.py:485
msgid "request time" msgid "request time"
msgstr "thời gian đăng ký" msgstr "thời gian đăng ký"
#: judge/models/profile.py:486 #: judge/models/profile.py:488
msgid "state" msgid "state"
msgstr "trạng thái" msgstr "trạng thái"
#: judge/models/profile.py:493 #: judge/models/profile.py:495
msgid "reason" msgid "reason"
msgstr "lý do" msgstr "lý do"
#: judge/models/profile.py:496 #: judge/models/profile.py:498
msgid "organization join request" msgid "organization join request"
msgstr "đơn đăng ký tham gia" msgstr "đơn đăng ký tham gia"
#: judge/models/profile.py:497 #: judge/models/profile.py:499
msgid "organization join requests" msgid "organization join requests"
msgstr "đơn đăng ký tham gia" msgstr "đơn đăng ký tham gia"
#: judge/models/profile.py:559 #: judge/models/profile.py:561
#, fuzzy #, fuzzy
#| msgid "last seen" #| msgid "last seen"
msgid "last visit" msgid "last visit"
@ -2768,16 +2825,16 @@ msgstr "Giới thiệu"
msgid "Custom Checker Sample" msgid "Custom Checker Sample"
msgstr "Hướng dẫn viết trình chấm" msgstr "Hướng dẫn viết trình chấm"
#: judge/views/blog.py:132 #: judge/views/blog.py:131
#, python-format #, python-format
msgid "Page %d of Posts" msgid "Page %d of Posts"
msgstr "Trang %d" msgstr "Trang %d"
#: judge/views/blog.py:172 #: judge/views/blog.py:171
msgid "Ticket feed" msgid "Ticket feed"
msgstr "Báo cáo" msgstr "Báo cáo"
#: judge/views/blog.py:189 #: judge/views/blog.py:188
msgid "Comment feed" msgid "Comment feed"
msgstr "Bình luận" msgstr "Bình luận"
@ -2793,8 +2850,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:866 #: judge/views/comment.py:267 judge/views/organization.py:883
#: judge/views/organization.py:1016 judge/views/organization.py:1211 #: judge/views/organization.py:1033 judge/views/organization.py:1228
msgid "Edited from site" msgid "Edited from site"
msgstr "Chỉnh sửa từ web" msgstr "Chỉnh sửa từ web"
@ -3156,34 +3213,34 @@ msgstr "Nhóm này là nhóm kín."
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:591 #: judge/views/organization.py:590
msgid "Leaving group" msgid "Leaving group"
msgstr "Rời nhóm" msgstr "Rời nhóm"
#: judge/views/organization.py:592 #: judge/views/organization.py:591
#, 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:618 #: 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:648 #: 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:682 #: judge/views/organization.py:680
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:686 #: judge/views/organization.py:684
#, 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:726 #: judge/views/organization.py:724
#, 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 "
@ -3192,81 +3249,94 @@ 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:744 #: judge/views/organization.py:742
#, 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:747 #: judge/views/organization.py:745
#, 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:787 #: judge/views/organization.py:785
#, 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:799 #: judge/views/organization.py:803
#, 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:819 judge/views/organization.py:827 #: judge/views/organization.py:823 judge/views/organization.py:831
#: judge/views/organization.py:840
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:820 #: judge/views/organization.py:824
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:828 #: judge/views/organization.py:832
#, 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:849 judge/views/organization.py:1005 #: judge/views/organization.py:841
#, fuzzy
#| msgid "Are you sure you want to leave this organization?"
msgid "The user you are trying to kick is an organization admin."
msgstr "Bạn có chắc muốn rời tổ chức?"
#: judge/views/organization.py:846
#, fuzzy
#| msgid "Add members"
msgid "Kicked member"
msgstr "Thêm thành viên"
#: judge/views/organization.py:866 judge/views/organization.py:1022
#, 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:877 templates/organization/search-form.html:19 #: judge/views/organization.py:894 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:892 #: judge/views/organization.py:909
msgid "Exceeded limit" msgid "Exceeded limit"
msgstr "" msgstr ""
#: judge/views/organization.py:893 #: judge/views/organization.py:910
#, 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:898 judge/views/organization.py:923 #: judge/views/organization.py:915 judge/views/organization.py:940
#: judge/views/organization.py:1096 #: judge/views/organization.py:1113
msgid "Added from site" msgid "Added from site"
msgstr "Thêm từ web" msgstr "Thêm từ web"
#: judge/views/organization.py:914 #: judge/views/organization.py:931
#: 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:957 judge/views/organization.py:1143 #: judge/views/organization.py:974 judge/views/organization.py:1160
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:958 #: judge/views/organization.py:975
#, 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:1009 templates/blog/blog.html:31 #: judge/views/organization.py:1026 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
@ -3277,27 +3347,27 @@ 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:1085 #: judge/views/organization.py:1102
#, 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:1137 #: judge/views/organization.py:1154
#, fuzzy #, fuzzy
#| msgid "Those who can edit this organization" #| msgid "Those who can edit this organization"
msgid "This blog does not belong to this organization" msgid "This blog does not belong to this organization"
msgstr "Những người có thể chỉnh sửa tổ chức" msgstr "Những người có thể chỉnh sửa tổ chức"
#: judge/views/organization.py:1139 #: judge/views/organization.py:1156
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:1196 #: judge/views/organization.py:1213
#, 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:1242 #: judge/views/organization.py:1259
#, 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"
@ -3570,8 +3640,8 @@ msgstr "Bài nộp trong <a href=\"{0}\">{1}</a>"
#: judge/views/submission.py:900 #: judge/views/submission.py:900
#, python-brace-format #, python-brace-format
msgid "" msgid ""
"<a href=\"{1}\">{0}</a>'s submissions for <a href=\"{3}\">{2}</a> in <a " "<a href=\"{1}\">{0}</a>'s submissions for <a href=\"{3}\">{2}</a> in <a href="
"href=\"{5}\">{4}</a>" "\"{5}\">{4}</a>"
msgstr "" msgstr ""
"Các bài nộp của <a href=\"{1}\">{0}</a> cho <a href=\"{3}\">{2}</a> trong <a " "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>" "href=\"{5}\">{4}</a>"
@ -3771,66 +3841,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:147 #: templates/base.html:146
msgid "Chat" msgid "Chat"
msgstr "Chat" msgstr "Chat"
#: templates/base.html:157 #: templates/base.html:156
msgid "Notification" msgid "Notification"
msgstr "Thông báo" msgstr "Thông báo"
#: templates/base.html:184 #: templates/base.html:183
msgid "Dark Mode" msgid "Dark Mode"
msgstr "" msgstr ""
#: templates/base.html:195 templates/profile-table.html:3 #: templates/base.html:194 templates/profile-table.html:3
msgid "Profile" msgid "Profile"
msgstr "Trang cá nhân" msgstr "Trang cá nhân"
#: templates/base.html:204 #: templates/base.html:203
msgid "Internal" msgid "Internal"
msgstr "Nội bộ" msgstr "Nội bộ"
#: templates/base.html:207 #: templates/base.html:206
msgid "Stats" msgid "Stats"
msgstr "Thống kê" msgstr "Thống kê"
#: templates/base.html:211 templates/user/user-tabs.html:11 #: templates/base.html:210 templates/user/user-tabs.html:11
msgid "Bookmarks" msgid "Bookmarks"
msgstr "Đã lưu" msgstr "Đã lưu"
#: templates/base.html:218 #: templates/base.html:217
#, 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:223 #: templates/base.html:222
msgid "Log out" msgid "Log out"
msgstr "Đăng xuất" msgstr "Đăng xuất"
#: templates/base.html:233 #: templates/base.html:232
#: 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:234 #: templates/base.html:233
msgid "Sign up" msgid "Sign up"
msgstr "Đăng ký" msgstr "Đăng ký"
#: templates/base.html:248 #: templates/base.html:247
msgid "spectating" msgid "spectating"
msgstr "đang theo dõi" msgstr "đang theo dõi"
#: templates/base.html:260 templates/contest/list.html:111 #: templates/base.html:259 templates/contest/list.html:111
msgid "In contest" msgid "In contest"
msgstr "Trong kỳ thi" msgstr "Trong kỳ thi"
#: templates/base.html:262 #: templates/base.html:261
msgid "Out contest" msgid "Out contest"
msgstr "Ngoài kỳ thi" msgstr "Ngoài kỳ thi"
#: templates/base.html:272 #: templates/base.html:271
msgid "This site works best with JavaScript enabled." msgid "This site works best with JavaScript enabled."
msgstr "" msgstr ""
@ -3870,10 +3940,6 @@ msgstr ""
msgid "News" msgid "News"
msgstr "Tin tức" msgstr "Tin tức"
#: templates/blog/list.html:47
msgid "Ticket"
msgstr "Báo cáo"
#: templates/blog/list.html:48 #: templates/blog/list.html:48
msgid "Events" msgid "Events"
msgstr "Sự kiện" msgstr "Sự kiện"
@ -3976,7 +4042,7 @@ msgstr "đã chỉnh sửa"
#: templates/comments/content-list.html:47 templates/notification/list.html:11 #: templates/comments/content-list.html:47 templates/notification/list.html:11
msgid "Link" msgid "Link"
msgstr "Link" msgstr "Đường dẫn"
#: templates/comments/content-list.html:57 #: templates/comments/content-list.html:57
#: templates/comments/content-list.html:63 #: templates/comments/content-list.html:63
@ -4156,8 +4222,8 @@ msgstr "G:i T, j F, Y"
#: templates/contest/contest-datetime.html:32 #: templates/contest/contest-datetime.html:32
#, python-format #, python-format
msgid "" msgid ""
"<b>%(time_limit)s</b> window between <b>%(start_time)s</b> and " "<b>%(time_limit)s</b> window between <b>%(start_time)s</b> and <b>"
"<b>%(end_time)s</b>" "%(end_time)s</b>"
msgstr "" msgstr ""
"Dài <b>%(time_limit)s</b> từ <b>%(start_time)s</b> đến <b>%(end_time)s</b>" "Dài <b>%(time_limit)s</b> từ <b>%(start_time)s</b> đến <b>%(end_time)s</b>"
@ -4907,7 +4973,7 @@ msgstr "Tìm kiếm nhóm"
msgid "Search organizations..." msgid "Search organizations..."
msgstr "Tìm kiếm nhóm" msgstr "Tìm kiếm nhóm"
#: templates/organization/users-table.html:15 #: templates/organization/users-table.html:16
msgid "Kick" msgid "Kick"
msgstr "Đuổi" msgstr "Đuổi"
@ -6262,6 +6328,9 @@ msgstr "Thông tin"
msgid "Check all" msgid "Check all"
msgstr "Chọn tất cả" msgstr "Chọn tất cả"
#~ msgid "A ticket is added or updated"
#~ msgstr "Báo cáo"
#~ msgid "Post time" #~ msgid "Post time"
#~ msgstr "Thời gian đăng" #~ msgstr "Thời gian đăng"
@ -6411,8 +6480,8 @@ msgstr "Chọn tất cả"
#~ msgstr "bình luận nữa" #~ msgstr "bình luận nữa"
#~ msgid "" #~ msgid ""
#~ "This comment is hidden due to too much negative feedback. Click <a " #~ "This comment is hidden due to too much negative feedback. Click <a href="
#~ "href=\"javascript:comment_show_content(%(id)s)\">here</a> to view it." #~ "\"javascript:comment_show_content(%(id)s)\">here</a> to view it."
#~ msgstr "" #~ msgstr ""
#~ "Bình luận bị ẩn vì nhiều phản hồi tiêu cực. Nhấp vào <a href=\"javascript:" #~ "Bình luận bị ẩn vì nhiều phản hồi tiêu cực. Nhấp vào <a href=\"javascript:"
#~ "comment_show_content(%(id)s)\">đây</a> để mở." #~ "comment_show_content(%(id)s)\">đây</a> để mở."

View file

@ -24,6 +24,9 @@ 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"
@ -39,6 +42,9 @@ 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 ""
@ -594,14 +600,8 @@ msgstr ""
msgid "z-function" msgid "z-function"
msgstr "" msgstr ""
msgid "Courses" #~ msgid "Insert Image"
msgstr "Khóa học" #~ msgstr "Chèn hình ảnh"
msgid "Bug Report" #~ msgid "Save"
msgstr "Báo cáo lỗi" #~ msgstr "Lưu"
msgid "Insert Image"
msgstr "Chèn hình ảnh"
msgid "Save"
msgstr "Lưu"

View file

@ -17,7 +17,7 @@
{{ link_user(notification.author_id) }} {{ link_user(notification.author_id) }}
</td> </td>
<td> <td>
{{ notification.category }} {{ notification.verbose_activity() }}
</td> </td>
<td> <td>
{% autoescape off %} {% autoescape off %}

View file

@ -9,11 +9,15 @@
{% block before_point %} {% block before_point %}
{% if can_edit %} {% if can_edit %}
<td> <td>
{% if not organization.is_admin(user) %}
<form action="{{ kick_url }}" method="POST" class="kick-form"> <form action="{{ kick_url }}" method="POST" class="kick-form">
{% csrf_token %} {% csrf_token %}
<input type="hidden" name="user" value="{{ user.id }}"> <input type="hidden" name="user" value="{{ user.id }}">
<a href="#" class="button small">{{ _('Kick') }}</a> <a href="#" class="button small">{{ _('Kick') }}</a>
</form> </form>
{% else %}
{{ _("Admin") }}
{% endif %}
</td> </td>
{% endif %} {% endif %}
{% endblock %} {% endblock %}