Update emails
This commit is contained in:
parent
164a712902
commit
af5bee5147
18 changed files with 481 additions and 170 deletions
20
dmoj/urls.py
20
dmoj/urls.py
|
@ -65,6 +65,7 @@ from judge.views import (
|
||||||
internal,
|
internal,
|
||||||
resolver,
|
resolver,
|
||||||
course,
|
course,
|
||||||
|
email,
|
||||||
)
|
)
|
||||||
from judge.views.problem_data import (
|
from judge.views.problem_data import (
|
||||||
ProblemDataView,
|
ProblemDataView,
|
||||||
|
@ -104,19 +105,19 @@ register_patterns = [
|
||||||
# confusing 404.
|
# confusing 404.
|
||||||
url(
|
url(
|
||||||
r"^activate/(?P<activation_key>\w+)/$",
|
r"^activate/(?P<activation_key>\w+)/$",
|
||||||
ActivationView.as_view(title="Activation key invalid"),
|
ActivationView.as_view(title=_("Activation key invalid")),
|
||||||
name="registration_activate",
|
name="registration_activate",
|
||||||
),
|
),
|
||||||
url(
|
url(
|
||||||
r"^register/$",
|
r"^register/$",
|
||||||
RegistrationView.as_view(title="Register"),
|
RegistrationView.as_view(title=_("Register")),
|
||||||
name="registration_register",
|
name="registration_register",
|
||||||
),
|
),
|
||||||
url(
|
url(
|
||||||
r"^register/complete/$",
|
r"^register/complete/$",
|
||||||
TitledTemplateView.as_view(
|
TitledTemplateView.as_view(
|
||||||
template_name="registration/registration_complete.html",
|
template_name="registration/registration_complete.html",
|
||||||
title="Registration Completed",
|
title=_("Registration Completed"),
|
||||||
),
|
),
|
||||||
name="registration_complete",
|
name="registration_complete",
|
||||||
),
|
),
|
||||||
|
@ -124,7 +125,7 @@ register_patterns = [
|
||||||
r"^register/closed/$",
|
r"^register/closed/$",
|
||||||
TitledTemplateView.as_view(
|
TitledTemplateView.as_view(
|
||||||
template_name="registration/registration_closed.html",
|
template_name="registration/registration_closed.html",
|
||||||
title="Registration not allowed",
|
title=_("Registration not allowed"),
|
||||||
),
|
),
|
||||||
name="registration_disallowed",
|
name="registration_disallowed",
|
||||||
),
|
),
|
||||||
|
@ -183,6 +184,17 @@ register_patterns = [
|
||||||
),
|
),
|
||||||
name="password_reset_done",
|
name="password_reset_done",
|
||||||
),
|
),
|
||||||
|
url(r"^email/change/$", email.email_change_view, name="email_change"),
|
||||||
|
url(
|
||||||
|
r"^email/change/verify/(?P<uidb64>[0-9A-Za-z]+)-(?P<token>.+)/$",
|
||||||
|
email.verify_email_view,
|
||||||
|
name="email_change_verify",
|
||||||
|
),
|
||||||
|
url(
|
||||||
|
r"^email/change/pending$",
|
||||||
|
email.email_change_pending_view,
|
||||||
|
name="email_change_pending",
|
||||||
|
),
|
||||||
url(r"^social/error/$", register.social_auth_error, name="social_auth_error"),
|
url(r"^social/error/$", register.social_auth_error, name="social_auth_error"),
|
||||||
url(r"^2fa/$", totp.TOTPLoginView.as_view(), name="login_2fa"),
|
url(r"^2fa/$", totp.TOTPLoginView.as_view(), name="login_2fa"),
|
||||||
url(r"^2fa/enable/$", totp.TOTPEnableView.as_view(), name="enable_2fa"),
|
url(r"^2fa/enable/$", totp.TOTPEnableView.as_view(), name="enable_2fa"),
|
||||||
|
|
18
judge/migrations/0163_email_change.py
Normal file
18
judge/migrations/0163_email_change.py
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
# Generated by Django 3.2.18 on 2023-08-25 00:19
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
("judge", "0162_profile_image"),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name="profile",
|
||||||
|
name="email_change_pending",
|
||||||
|
field=models.EmailField(blank=True, max_length=254, null=True),
|
||||||
|
),
|
||||||
|
]
|
|
@ -237,6 +237,7 @@ class Profile(models.Model):
|
||||||
help_text=_("Notes for administrators regarding this user."),
|
help_text=_("Notes for administrators regarding this user."),
|
||||||
)
|
)
|
||||||
profile_image = models.ImageField(upload_to=profile_image_path, null=True)
|
profile_image = models.ImageField(upload_to=profile_image_path, null=True)
|
||||||
|
email_change_pending = models.EmailField(blank=True, null=True)
|
||||||
|
|
||||||
@cached_property
|
@cached_property
|
||||||
def organization(self):
|
def organization(self):
|
||||||
|
|
20
judge/utils/email_render.py
Normal file
20
judge/utils/email_render.py
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
from django.template.loader import render_to_string
|
||||||
|
from django.contrib.sites.shortcuts import get_current_site
|
||||||
|
from django.conf import settings
|
||||||
|
|
||||||
|
|
||||||
|
def render_email_message(request, contexts):
|
||||||
|
current_site = get_current_site(request)
|
||||||
|
email_contexts = {
|
||||||
|
"username": request.user.username,
|
||||||
|
"domain": current_site.domain,
|
||||||
|
"protocol": "https" if request.is_secure() else "http",
|
||||||
|
"site_name": settings.SITE_NAME,
|
||||||
|
"message": None,
|
||||||
|
"title": None,
|
||||||
|
"button_text": "Click here",
|
||||||
|
"url_path": None,
|
||||||
|
}
|
||||||
|
email_contexts.update(contexts)
|
||||||
|
message = render_to_string("general_email.html", email_contexts)
|
||||||
|
return message
|
104
judge/views/email.py
Normal file
104
judge/views/email.py
Normal file
|
@ -0,0 +1,104 @@
|
||||||
|
from django.contrib.auth.tokens import default_token_generator
|
||||||
|
from django.core.mail import send_mail
|
||||||
|
from django.shortcuts import render, redirect
|
||||||
|
from django.utils.http import urlsafe_base64_encode, urlsafe_base64_decode
|
||||||
|
from django.utils.encoding import force_bytes, force_text
|
||||||
|
from django.conf import settings
|
||||||
|
from django import forms
|
||||||
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
from django.urls import reverse
|
||||||
|
from django.contrib.auth.decorators import login_required
|
||||||
|
from django.contrib.auth.models import User
|
||||||
|
|
||||||
|
from urllib.parse import urlencode, urlunparse, urlparse
|
||||||
|
|
||||||
|
from judge.models import Profile
|
||||||
|
from judge.utils.email_render import render_email_message
|
||||||
|
|
||||||
|
|
||||||
|
class EmailChangeForm(forms.Form):
|
||||||
|
new_email = forms.EmailField(label=_("New Email"))
|
||||||
|
|
||||||
|
def clean_new_email(self):
|
||||||
|
new_email = self.cleaned_data.get("new_email")
|
||||||
|
if User.objects.filter(email=new_email).exists():
|
||||||
|
raise forms.ValidationError(_("An account with this email already exists."))
|
||||||
|
return new_email
|
||||||
|
|
||||||
|
|
||||||
|
@login_required
|
||||||
|
def email_change_view(request):
|
||||||
|
form = EmailChangeForm(request.POST or None)
|
||||||
|
|
||||||
|
if request.method == "POST" and form.is_valid():
|
||||||
|
new_email = request.POST.get("new_email")
|
||||||
|
user = request.user
|
||||||
|
profile = request.profile
|
||||||
|
|
||||||
|
# Generate a token for email verification
|
||||||
|
token = default_token_generator.make_token(user)
|
||||||
|
uid = urlsafe_base64_encode(force_bytes(user.pk))
|
||||||
|
|
||||||
|
# Send the email to the user
|
||||||
|
subject = _(f"{settings.SITE_NAME} - Email Change Request")
|
||||||
|
email_contexts = {
|
||||||
|
"message": _(
|
||||||
|
"We have received a request to change your email to this email. Click the button below to change your email:"
|
||||||
|
),
|
||||||
|
"title": _("Email Change"),
|
||||||
|
"button_text": _("Change Email"),
|
||||||
|
"url_path": reverse(
|
||||||
|
"email_change_verify", kwargs={"uidb64": uid, "token": token}
|
||||||
|
),
|
||||||
|
}
|
||||||
|
message = render_email_message(request, email_contexts)
|
||||||
|
send_mail(subject, message, settings.EMAIL_HOST_USER, [new_email])
|
||||||
|
profile.email_change_pending = new_email
|
||||||
|
profile.save()
|
||||||
|
return redirect("email_change_pending")
|
||||||
|
|
||||||
|
return render(
|
||||||
|
request,
|
||||||
|
"email_change/email_change.html",
|
||||||
|
{
|
||||||
|
"form": form,
|
||||||
|
"title": _("Change email"),
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def verify_email_view(request, uidb64, token):
|
||||||
|
try:
|
||||||
|
uid = force_text(urlsafe_base64_decode(uidb64))
|
||||||
|
user = User.objects.get(pk=uid)
|
||||||
|
except (TypeError, ValueError, OverflowError, User.DoesNotExist):
|
||||||
|
user = None
|
||||||
|
if user is not None and default_token_generator.check_token(user, token):
|
||||||
|
# Update the user's email address
|
||||||
|
profile = Profile.objects.get(user=user)
|
||||||
|
new_email = profile.email_change_pending
|
||||||
|
if new_email:
|
||||||
|
user.email = new_email
|
||||||
|
profile.email_change_pending = None
|
||||||
|
user.save()
|
||||||
|
profile.save()
|
||||||
|
|
||||||
|
return render(
|
||||||
|
request,
|
||||||
|
"email_change/email_change_success.html",
|
||||||
|
{"title": _("Success"), "user": user},
|
||||||
|
)
|
||||||
|
|
||||||
|
return render(
|
||||||
|
request, "email_change/email_change_failure.html", {"title": _("Invalid")}
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def email_change_pending_view(request):
|
||||||
|
return render(
|
||||||
|
request,
|
||||||
|
"email_change/email_change_pending.html",
|
||||||
|
{
|
||||||
|
"title": _("Email change pending"),
|
||||||
|
},
|
||||||
|
)
|
|
@ -15,7 +15,7 @@ from registration.backends.default.views import (
|
||||||
from registration.forms import RegistrationForm
|
from registration.forms import RegistrationForm
|
||||||
from sortedm2m.forms import SortedMultipleChoiceField
|
from sortedm2m.forms import SortedMultipleChoiceField
|
||||||
|
|
||||||
from judge.models import Language, Organization, Profile, TIMEZONE
|
from judge.models import Language, Profile, TIMEZONE
|
||||||
from judge.utils.recaptcha import ReCaptchaField, ReCaptchaWidget
|
from judge.utils.recaptcha import ReCaptchaField, ReCaptchaWidget
|
||||||
from judge.widgets import Select2MultipleWidget, Select2Widget
|
from judge.widgets import Select2MultipleWidget, Select2Widget
|
||||||
|
|
||||||
|
@ -43,29 +43,10 @@ class CustomRegistrationForm(RegistrationForm):
|
||||||
empty_label=None,
|
empty_label=None,
|
||||||
widget=Select2Widget(attrs={"style": "width:100%"}),
|
widget=Select2Widget(attrs={"style": "width:100%"}),
|
||||||
)
|
)
|
||||||
organizations = SortedMultipleChoiceField(
|
|
||||||
queryset=Organization.objects.filter(is_open=True),
|
|
||||||
label=_("Groups"),
|
|
||||||
required=False,
|
|
||||||
widget=Select2MultipleWidget(attrs={"style": "width:100%"}),
|
|
||||||
)
|
|
||||||
|
|
||||||
if ReCaptchaField is not None:
|
if ReCaptchaField is not None:
|
||||||
captcha = ReCaptchaField(widget=ReCaptchaWidget())
|
captcha = ReCaptchaField(widget=ReCaptchaWidget())
|
||||||
|
|
||||||
def clean_organizations(self):
|
|
||||||
organizations = self.cleaned_data.get("organizations") or []
|
|
||||||
max_orgs = settings.DMOJ_USER_MAX_ORGANIZATION_COUNT
|
|
||||||
|
|
||||||
if sum(org.is_open for org in organizations) > max_orgs:
|
|
||||||
raise forms.ValidationError(
|
|
||||||
_("You may not be part of more than {count} public groups.").format(
|
|
||||||
count=max_orgs
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
return self.cleaned_data["organizations"]
|
|
||||||
|
|
||||||
def clean_email(self):
|
def clean_email(self):
|
||||||
if User.objects.filter(email=self.cleaned_data["email"]).exists():
|
if User.objects.filter(email=self.cleaned_data["email"]).exists():
|
||||||
raise forms.ValidationError(
|
raise forms.ValidationError(
|
||||||
|
@ -116,7 +97,6 @@ class RegistrationView(OldRegistrationView):
|
||||||
cleaned_data = form.cleaned_data
|
cleaned_data = form.cleaned_data
|
||||||
profile.timezone = cleaned_data["timezone"]
|
profile.timezone = cleaned_data["timezone"]
|
||||||
profile.language = cleaned_data["language"]
|
profile.language = cleaned_data["language"]
|
||||||
profile.organizations.add(*cleaned_data["organizations"])
|
|
||||||
profile.save()
|
profile.save()
|
||||||
return user
|
return user
|
||||||
|
|
||||||
|
|
|
@ -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: 2023-08-24 23:09+0700\n"
|
"POT-Creation-Date: 2023-08-26 03:32+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"
|
||||||
|
@ -21,7 +21,7 @@ msgstr ""
|
||||||
#: chat_box/models.py:31 chat_box/models.py:54 chat_box/models.py:68
|
#: chat_box/models.py:31 chat_box/models.py:54 chat_box/models.py:68
|
||||||
#: judge/admin/interface.py:150 judge/models/contest.py:636
|
#: judge/admin/interface.py:150 judge/models/contest.py:636
|
||||||
#: judge/models/contest.py:845 judge/models/course.py:115
|
#: judge/models/contest.py:845 judge/models/course.py:115
|
||||||
#: judge/models/profile.py:374 judge/models/profile.py:452
|
#: judge/models/profile.py:375 judge/models/profile.py:453
|
||||||
msgid "user"
|
msgid "user"
|
||||||
msgstr "người dùng"
|
msgstr "người dùng"
|
||||||
|
|
||||||
|
@ -49,11 +49,27 @@ msgstr "Tiếng Việt"
|
||||||
msgid "English"
|
msgid "English"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: dmoj/urls.py:135
|
#: dmoj/urls.py:108
|
||||||
|
msgid "Activation key invalid"
|
||||||
|
msgstr "Mã kích hoạt không hợp lệ"
|
||||||
|
|
||||||
|
#: dmoj/urls.py:113
|
||||||
|
msgid "Register"
|
||||||
|
msgstr "Đăng ký"
|
||||||
|
|
||||||
|
#: dmoj/urls.py:120
|
||||||
|
msgid "Registration Completed"
|
||||||
|
msgstr "Đăng ký hoàn thành"
|
||||||
|
|
||||||
|
#: dmoj/urls.py:128
|
||||||
|
msgid "Registration not allowed"
|
||||||
|
msgstr "Đăng ký không thành công"
|
||||||
|
|
||||||
|
#: dmoj/urls.py:136
|
||||||
msgid "Login"
|
msgid "Login"
|
||||||
msgstr "Đăng nhập"
|
msgstr "Đăng nhập"
|
||||||
|
|
||||||
#: dmoj/urls.py:212 templates/base.html:209
|
#: dmoj/urls.py:216 templates/base.html:209
|
||||||
#: templates/organization/org-left-sidebar.html:2
|
#: templates/organization/org-left-sidebar.html:2
|
||||||
msgid "Home"
|
msgid "Home"
|
||||||
msgstr "Trang chủ"
|
msgstr "Trang chủ"
|
||||||
|
@ -293,13 +309,13 @@ msgid "User"
|
||||||
msgstr "Thành viên"
|
msgstr "Thành viên"
|
||||||
|
|
||||||
#: judge/admin/profile.py:132 templates/registration/registration_form.html:40
|
#: judge/admin/profile.py:132 templates/registration/registration_form.html:40
|
||||||
#: templates/user/import/table_csv.html:8
|
#: templates/user/edit-profile.html:116 templates/user/import/table_csv.html:8
|
||||||
msgid "Email"
|
msgid "Email"
|
||||||
msgstr "Email"
|
msgstr "Email"
|
||||||
|
|
||||||
#: judge/admin/profile.py:138 judge/views/register.py:36
|
#: judge/admin/profile.py:138 judge/views/register.py:36
|
||||||
#: templates/registration/registration_form.html:68
|
#: templates/registration/registration_form.html:68
|
||||||
#: templates/user/edit-profile.html:119
|
#: templates/user/edit-profile.html:140
|
||||||
msgid "Timezone"
|
msgid "Timezone"
|
||||||
msgstr "Múi giờ"
|
msgstr "Múi giờ"
|
||||||
|
|
||||||
|
@ -497,7 +513,7 @@ msgstr "Tên đăng nhập"
|
||||||
|
|
||||||
#: judge/forms.py:428 templates/registration/registration_form.html:46
|
#: judge/forms.py:428 templates/registration/registration_form.html:46
|
||||||
#: templates/registration/registration_form.html:60
|
#: templates/registration/registration_form.html:60
|
||||||
#: templates/user/import/table_csv.html:5
|
#: templates/user/edit-profile.html:108 templates/user/import/table_csv.html:5
|
||||||
msgid "Password"
|
msgid "Password"
|
||||||
msgstr "Mật khẩu"
|
msgstr "Mật khẩu"
|
||||||
|
|
||||||
|
@ -1972,7 +1988,7 @@ msgid ""
|
||||||
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:136 judge/models/profile.py:165
|
#: judge/models/profile.py:136 judge/models/profile.py:165
|
||||||
#: judge/models/profile.py:380 judge/models/profile.py:459
|
#: judge/models/profile.py:381 judge/models/profile.py:460
|
||||||
msgid "organization"
|
msgid "organization"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
@ -2078,35 +2094,35 @@ msgstr "ghi chú nội bộ"
|
||||||
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:367
|
#: judge/models/profile.py:368
|
||||||
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:368
|
#: judge/models/profile.py:369
|
||||||
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:384
|
#: judge/models/profile.py:385
|
||||||
msgid "request time"
|
msgid "request time"
|
||||||
msgstr "thời gian đăng ký"
|
msgstr "thời gian đăng ký"
|
||||||
|
|
||||||
#: judge/models/profile.py:387
|
#: judge/models/profile.py:388
|
||||||
msgid "state"
|
msgid "state"
|
||||||
msgstr "trạng thái"
|
msgstr "trạng thái"
|
||||||
|
|
||||||
#: judge/models/profile.py:394
|
#: judge/models/profile.py:395
|
||||||
msgid "reason"
|
msgid "reason"
|
||||||
msgstr "lý do"
|
msgstr "lý do"
|
||||||
|
|
||||||
#: judge/models/profile.py:397
|
#: judge/models/profile.py:398
|
||||||
msgid "organization join request"
|
msgid "organization join request"
|
||||||
msgstr "đơn đăng ký tham gia"
|
msgstr "đơn đăng ký tham gia"
|
||||||
|
|
||||||
#: judge/models/profile.py:398
|
#: judge/models/profile.py:399
|
||||||
msgid "organization join requests"
|
msgid "organization join requests"
|
||||||
msgstr "đơn đăng ký tham gia"
|
msgstr "đơn đăng ký tham gia"
|
||||||
|
|
||||||
#: judge/models/profile.py:464
|
#: judge/models/profile.py:465
|
||||||
#, fuzzy
|
#, fuzzy
|
||||||
#| msgid "last seen"
|
#| msgid "last seen"
|
||||||
msgid "last visit"
|
msgid "last visit"
|
||||||
|
@ -2839,6 +2855,55 @@ msgstr "Mô tả vấn đề"
|
||||||
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"
|
||||||
|
|
||||||
|
#: judge/views/email.py:19
|
||||||
|
#, fuzzy
|
||||||
|
#| msgid "Email"
|
||||||
|
msgid "New Email"
|
||||||
|
msgstr "Email"
|
||||||
|
|
||||||
|
#: judge/views/email.py:23
|
||||||
|
#, fuzzy
|
||||||
|
#| msgid "Contest with key already exists."
|
||||||
|
msgid "An account with this email already exists."
|
||||||
|
msgstr "Mã kỳ thi đã tồn tại."
|
||||||
|
|
||||||
|
#: judge/views/email.py:41
|
||||||
|
#, python-brace-format
|
||||||
|
msgid "{settings.SITE_NAME} - Email Change Request"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: judge/views/email.py:43
|
||||||
|
msgid ""
|
||||||
|
"We have received a request to change your email to this email. Click the "
|
||||||
|
"button below to change your email:"
|
||||||
|
msgstr ""
|
||||||
|
"Chúng tôi đã nhận được yêu cầu thay đổi địa chỉ email của bạn thành địa chỉ "
|
||||||
|
"email này. Vui lòng nhấp vào nút bên dưới để thay đổi địa chỉ email của bạn:"
|
||||||
|
|
||||||
|
#: judge/views/email.py:44
|
||||||
|
msgid "Email Change"
|
||||||
|
msgstr "Thay đổi Email"
|
||||||
|
|
||||||
|
#: judge/views/email.py:45
|
||||||
|
msgid "Change Email"
|
||||||
|
msgstr "Thay đổi Email"
|
||||||
|
|
||||||
|
#: judge/views/email.py:56 templates/user/edit-profile.html:120
|
||||||
|
msgid "Change email"
|
||||||
|
msgstr "Thay đổi email"
|
||||||
|
|
||||||
|
#: judge/views/email.py:76
|
||||||
|
msgid "Success"
|
||||||
|
msgstr "Thành công"
|
||||||
|
|
||||||
|
#: judge/views/email.py:78
|
||||||
|
msgid "Invalid"
|
||||||
|
msgstr "Không hợp lệ"
|
||||||
|
|
||||||
|
#: judge/views/email.py:83
|
||||||
|
msgid "Email change pending"
|
||||||
|
msgstr "Yêu cầu thay đổi email đang đợi xác thực."
|
||||||
|
|
||||||
#: judge/views/error.py:17
|
#: judge/views/error.py:17
|
||||||
msgid "404 error"
|
msgid "404 error"
|
||||||
msgstr "Lỗi 404"
|
msgstr "Lỗi 404"
|
||||||
|
@ -2902,19 +2967,17 @@ 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:193 judge/views/organization.py:337
|
#: judge/views/organization.py:193 judge/views/organization.py:337
|
||||||
#, fuzzy
|
|
||||||
#| msgid "Can't edit organization"
|
|
||||||
msgid "Can't access organization"
|
msgid "Can't access organization"
|
||||||
msgstr "Không thể chỉnh sửa tổ chức"
|
msgstr "Không thể truy cập nhóm"
|
||||||
|
|
||||||
#: judge/views/organization.py:194 judge/views/organization.py:338
|
#: judge/views/organization.py:194 judge/views/organization.py:338
|
||||||
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:230 judge/views/register.py:48
|
#: judge/views/organization.py:230 judge/views/stats.py:184
|
||||||
#: judge/views/stats.py:184 templates/contest/list.html:89
|
#: templates/contest/list.html:89 templates/problem/list-base.html:97
|
||||||
#: templates/problem/list-base.html:97 templates/stats/site.html:33
|
#: templates/stats/site.html:33 templates/user/user-left-sidebar.html:4
|
||||||
#: 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"
|
||||||
|
|
||||||
|
@ -2941,7 +3004,7 @@ msgstr "Bạn đã ở trong nhóm."
|
||||||
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:510 judge/views/register.py:62
|
#: judge/views/organization.py:510
|
||||||
#, 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."
|
||||||
|
@ -3205,11 +3268,11 @@ msgstr "Các bài nộp tốt nhất cho <a href=\"{1}\">{0}</a>"
|
||||||
msgid "A username must contain letters, numbers, or underscores"
|
msgid "A username must contain letters, numbers, or underscores"
|
||||||
msgstr "Tên đăng nhập phải chứa ký tự, chữ số, hoặc dấu gạch dưới"
|
msgstr "Tên đăng nhập phải chứa ký tự, chữ số, hoặc dấu gạch dưới"
|
||||||
|
|
||||||
#: judge/views/register.py:42 templates/user/edit-profile.html:123
|
#: judge/views/register.py:42 templates/user/edit-profile.html:144
|
||||||
msgid "Preferred language"
|
msgid "Preferred language"
|
||||||
msgstr "Ngôn ngữ ưa thích"
|
msgstr "Ngôn ngữ ưa thích"
|
||||||
|
|
||||||
#: judge/views/register.py:73
|
#: judge/views/register.py:54
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid ""
|
msgid ""
|
||||||
"The email address \"%s\" is already taken. Only one registration is allowed "
|
"The email address \"%s\" is already taken. Only one registration is allowed "
|
||||||
|
@ -3217,7 +3280,7 @@ msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Email \"%s\" đã được sử dụng. Mỗi email chỉ có thể đăng ký một tài khoản."
|
"Email \"%s\" đã được sử dụng. Mỗi email chỉ có thể đăng ký một tài khoản."
|
||||||
|
|
||||||
#: judge/views/register.py:85
|
#: judge/views/register.py:66
|
||||||
msgid ""
|
msgid ""
|
||||||
"Your email provider is not allowed due to history of abuse. Please use a "
|
"Your email provider is not allowed due to history of abuse. Please use a "
|
||||||
"reputable email provider."
|
"reputable email provider."
|
||||||
|
@ -3225,11 +3288,11 @@ msgstr ""
|
||||||
"Your email provider is not allowed due to history of abuse. Please use a "
|
"Your email provider is not allowed due to history of abuse. Please use a "
|
||||||
"reputable email provider."
|
"reputable email provider."
|
||||||
|
|
||||||
#: judge/views/register.py:93 judge/views/register.py:131
|
#: judge/views/register.py:74 judge/views/register.py:111
|
||||||
msgid "Registration"
|
msgid "Registration"
|
||||||
msgstr "Đăng ký"
|
msgstr "Đăng ký"
|
||||||
|
|
||||||
#: judge/views/register.py:145
|
#: judge/views/register.py:125
|
||||||
msgid "Authentication failure"
|
msgid "Authentication failure"
|
||||||
msgstr "Xác thực thất bại"
|
msgstr "Xác thực thất bại"
|
||||||
|
|
||||||
|
@ -4185,11 +4248,11 @@ msgstr "Khôi phục kết quả"
|
||||||
msgid "Disqualify"
|
msgid "Disqualify"
|
||||||
msgstr "Hủy kết quả"
|
msgstr "Hủy kết quả"
|
||||||
|
|
||||||
#: templates/contest/ranking-table.html:54 templates/user/edit-profile.html:96
|
#: templates/contest/ranking-table.html:54 templates/user/edit-profile.html:100
|
||||||
msgid "Fullname"
|
msgid "Fullname"
|
||||||
msgstr "Tên đầy đủ"
|
msgstr "Tên đầy đủ"
|
||||||
|
|
||||||
#: templates/contest/ranking-table.html:55 templates/user/edit-profile.html:100
|
#: templates/contest/ranking-table.html:55 templates/user/edit-profile.html:104
|
||||||
#: templates/user/import/table_csv.html:7
|
#: templates/user/import/table_csv.html:7
|
||||||
msgid "School"
|
msgid "School"
|
||||||
msgstr "Trường"
|
msgstr "Trường"
|
||||||
|
@ -4262,6 +4325,26 @@ msgstr "Còn"
|
||||||
msgid "Upcoming contests"
|
msgid "Upcoming contests"
|
||||||
msgstr "Kỳ thi sắp diễn ra"
|
msgstr "Kỳ thi sắp diễn ra"
|
||||||
|
|
||||||
|
#: templates/email_change/email_change.html:19
|
||||||
|
msgid "Verify Email"
|
||||||
|
msgstr "Xác thực Email"
|
||||||
|
|
||||||
|
#: templates/email_change/email_change_failure.html:3
|
||||||
|
msgid "Invalid reset link."
|
||||||
|
msgstr "Đường dẫn không hợp lệ"
|
||||||
|
|
||||||
|
#: templates/email_change/email_change_pending.html:4
|
||||||
|
msgid "An email was sent to"
|
||||||
|
msgstr "Email đã được gửi đến"
|
||||||
|
|
||||||
|
#: templates/email_change/email_change_pending.html:4
|
||||||
|
msgid "If you don't see it, kindly check your spam folder as well."
|
||||||
|
msgstr "Nếu bạn không tìm thấy nó, vui lòng kiểm tra thư mục spam của bạn."
|
||||||
|
|
||||||
|
#: templates/email_change/email_change_success.html:3
|
||||||
|
msgid "Your email was sucessfully changed to"
|
||||||
|
msgstr "Bạn đã đổi email thành công."
|
||||||
|
|
||||||
#: templates/feed/has_next.html:3
|
#: templates/feed/has_next.html:3
|
||||||
msgid "View more"
|
msgid "View more"
|
||||||
msgstr "Xem thêm"
|
msgstr "Xem thêm"
|
||||||
|
@ -4290,6 +4373,10 @@ msgstr "Dừng"
|
||||||
msgid "Continue"
|
msgid "Continue"
|
||||||
msgstr "Tiếp tục"
|
msgstr "Tiếp tục"
|
||||||
|
|
||||||
|
#: templates/general_email.html:15
|
||||||
|
msgid "Dear"
|
||||||
|
msgstr "Xin chào"
|
||||||
|
|
||||||
#: templates/internal/left-sidebar.html:3
|
#: templates/internal/left-sidebar.html:3
|
||||||
msgid "Average speed"
|
msgid "Average speed"
|
||||||
msgstr "Tốc độ trung bình"
|
msgstr "Tốc độ trung bình"
|
||||||
|
@ -4505,6 +4592,10 @@ msgstr "Từ chối"
|
||||||
msgid "Kick"
|
msgid "Kick"
|
||||||
msgstr "Đuổi"
|
msgstr "Đuổi"
|
||||||
|
|
||||||
|
#: templates/pagedown.html:9
|
||||||
|
msgid "Update Preview"
|
||||||
|
msgstr "Cập nhật xem trước"
|
||||||
|
|
||||||
#: templates/problem/clone.html:37
|
#: templates/problem/clone.html:37
|
||||||
msgid "Enter a new code for the cloned problem:"
|
msgid "Enter a new code for the cloned problem:"
|
||||||
msgstr "Nhập mã bài mới cho bài tập được nhân bản:"
|
msgstr "Nhập mã bài mới cho bài tập được nhân bản:"
|
||||||
|
@ -4994,6 +5085,37 @@ msgstr "%(key)s không phải mã xác thực hợp lệ."
|
||||||
msgid "Your account has been successfully activated."
|
msgid "Your account has been successfully activated."
|
||||||
msgstr "Tài khoản được kích hoạt thành công."
|
msgstr "Tài khoản được kích hoạt thành công."
|
||||||
|
|
||||||
|
#: templates/registration/activation_email.html:2
|
||||||
|
msgid "Account activation"
|
||||||
|
msgstr "Kích hoạt tài khoản"
|
||||||
|
|
||||||
|
#: templates/registration/activation_email.html:3
|
||||||
|
#, python-format
|
||||||
|
msgid ""
|
||||||
|
"Thanks for registering! We're glad to have you. The last step is activating "
|
||||||
|
"your account. Please activate your account in the next %(expiration_days)d "
|
||||||
|
"days."
|
||||||
|
msgstr ""
|
||||||
|
"Cảm ơn bạn đã đăng ký! Chúng tôi rất vui được chào đón bạn. Bước cuối cùng "
|
||||||
|
"là kích hoạt tài khoản của bạn. Vui lòng kích hoạt tài khoản trong vòng "
|
||||||
|
"%(expiration_days)d ngày."
|
||||||
|
|
||||||
|
#: templates/registration/activation_email.html:5
|
||||||
|
msgid "Activate"
|
||||||
|
msgstr "Kích hoạt"
|
||||||
|
|
||||||
|
#: templates/registration/activation_email.html:10
|
||||||
|
msgid ""
|
||||||
|
"Alternatively, you can reply to this message to activate your account. Your "
|
||||||
|
"reply must keep the following text intact for this to work:"
|
||||||
|
msgstr ""
|
||||||
|
"Hoặc bạn có thể trả lời tin nhắn này để kích hoạt tài khoản của bạn. Email "
|
||||||
|
"trả lời của bạn phải giữ nguyên đoạn văn sau đây:"
|
||||||
|
|
||||||
|
#: templates/registration/activation_email.html:16
|
||||||
|
msgid "See you soon!"
|
||||||
|
msgstr "Hẹn sớm gặp lại bạn!"
|
||||||
|
|
||||||
#: templates/registration/login.html:9
|
#: templates/registration/login.html:9
|
||||||
msgid "Invalid username or password."
|
msgid "Invalid username or password."
|
||||||
msgstr "Tên đăng nhập hoặc mật khẩu không hợp lệ."
|
msgstr "Tên đăng nhập hoặc mật khẩu không hợp lệ."
|
||||||
|
@ -5032,6 +5154,7 @@ msgid "Your password has been set. You may go ahead and log in now"
|
||||||
msgstr "Mật khẩu đã được cập nhật. Hãy thử đăng nhập lại"
|
msgstr "Mật khẩu đã được cập nhật. Hãy thử đăng nhập lại"
|
||||||
|
|
||||||
#: templates/registration/password_reset_confirm.html:9
|
#: templates/registration/password_reset_confirm.html:9
|
||||||
|
#: templates/registration/password_reset_email.html:5
|
||||||
msgid "Reset Password"
|
msgid "Reset Password"
|
||||||
msgstr "Reset mật khẩu"
|
msgstr "Reset mật khẩu"
|
||||||
|
|
||||||
|
@ -5039,7 +5162,7 @@ msgstr "Reset mật khẩu"
|
||||||
msgid ""
|
msgid ""
|
||||||
"We've emailed you instructions for setting your password. You should be "
|
"We've emailed you instructions for setting your password. You should be "
|
||||||
"receiving them shortly."
|
"receiving them shortly."
|
||||||
msgstr "Kiểm tra email để xem hướng dẫn đặt mật khẩu."
|
msgstr "Chúng tôi đã gửi email cho bạn để đặt lại mật khẩu."
|
||||||
|
|
||||||
#: templates/registration/password_reset_done.html:5
|
#: templates/registration/password_reset_done.html:5
|
||||||
msgid ""
|
msgid ""
|
||||||
|
@ -5047,13 +5170,25 @@ msgid ""
|
||||||
"you registered with, and check your spam folder."
|
"you registered with, and check your spam folder."
|
||||||
msgstr "Nếu bạn không nhận được email, hãy kiểm tra hộp thư rác (spam)."
|
msgstr "Nếu bạn không nhận được email, hãy kiểm tra hộp thư rác (spam)."
|
||||||
|
|
||||||
|
#: templates/registration/password_reset_email.html:2
|
||||||
|
msgid "Password Reset"
|
||||||
|
msgstr "Đặt lại mật khẩu"
|
||||||
|
|
||||||
|
#: templates/registration/password_reset_email.html:3
|
||||||
|
msgid ""
|
||||||
|
"We have received a request to reset your password. Click the button below to "
|
||||||
|
"reset your password:"
|
||||||
|
msgstr ""
|
||||||
|
"Chúng tôi đã nhận được yêu cầu đặt lại mật khẩu của bạn. Nhấn vào nút bên "
|
||||||
|
"dưới để đặt lại mật khẩu của bạn:"
|
||||||
|
|
||||||
#: templates/registration/password_reset_email.txt:1
|
#: templates/registration/password_reset_email.txt:1
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid ""
|
msgid ""
|
||||||
"You're receiving this email because you requested a password reset for your "
|
"You're receiving this email because you requested a password reset for your "
|
||||||
"user account at %(site_name)s."
|
"user account at %(site_name)s."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Bạn nhận được email này vì bạn đã yêu cầu reset mật khẩu tại %(site_name)s."
|
"Bạn nhận được email này vì bạn đã yêu cầu đặt lại mật khẩu tại %(site_name)s."
|
||||||
|
|
||||||
#: templates/registration/password_reset_email.txt:3
|
#: templates/registration/password_reset_email.txt:3
|
||||||
msgid "Please go to the following page and choose a new password:"
|
msgid "Please go to the following page and choose a new password:"
|
||||||
|
@ -5075,7 +5210,7 @@ msgstr "%(site_name)s team"
|
||||||
#: templates/registration/password_reset_subject.txt:1
|
#: templates/registration/password_reset_subject.txt:1
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Password reset on %(site_name)s"
|
msgid "Password reset on %(site_name)s"
|
||||||
msgstr "Reset mật khẩu trên %(site_name)s"
|
msgstr "Đặt lại mật khẩu trên %(site_name)s"
|
||||||
|
|
||||||
#: templates/registration/profile_creation.html:36
|
#: templates/registration/profile_creation.html:36
|
||||||
#: templates/registration/username_select.html:7
|
#: templates/registration/username_select.html:7
|
||||||
|
@ -5089,8 +5224,9 @@ msgstr "Đăng ký hiện tại đã bị dừng. Hãy liên hệ admin."
|
||||||
#: templates/registration/registration_complete.html:3
|
#: templates/registration/registration_complete.html:3
|
||||||
msgid ""
|
msgid ""
|
||||||
"You have successfully been registered. An email has been sent to the email "
|
"You have successfully been registered. An email has been sent to the email "
|
||||||
"address you provided to confirm your registration."
|
"address you provided to confirm your registration. If you don't see it, "
|
||||||
msgstr "Bạn đã đăng ký thành công. Kiểm tra email để hoàn thành việc xác thực."
|
"kindly check your spam folder as well."
|
||||||
|
msgstr "Bạn đã đăng ký thành công. Kiểm tra email để hoàn thành việc xác thực. Nếu bạn không tìm thấy nó, vui lòng kiểm tra thư mục spam của bạn."
|
||||||
|
|
||||||
#: templates/registration/registration_form.html:61
|
#: templates/registration/registration_form.html:61
|
||||||
msgid "(again, for confirmation)"
|
msgid "(again, for confirmation)"
|
||||||
|
@ -5106,21 +5242,9 @@ msgstr "chọn từ bản đồ"
|
||||||
|
|
||||||
#: templates/registration/registration_form.html:78
|
#: templates/registration/registration_form.html:78
|
||||||
msgid "Default language"
|
msgid "Default language"
|
||||||
msgstr "Ngôn ngữ ưa thích"
|
msgstr "Ngôn ngữ mặc định"
|
||||||
|
|
||||||
#: templates/registration/registration_form.html:81
|
#: templates/registration/registration_form.html:89
|
||||||
msgid "Affiliated organizations"
|
|
||||||
msgstr "Tổ chức bạn muốn tham gia"
|
|
||||||
|
|
||||||
#: templates/registration/registration_form.html:97
|
|
||||||
msgid "By registering, you agree to our"
|
|
||||||
msgstr "Bạn đồng ý với"
|
|
||||||
|
|
||||||
#: templates/registration/registration_form.html:98
|
|
||||||
msgid "Terms & Conditions"
|
|
||||||
msgstr "Điều khoản của chúng tôi"
|
|
||||||
|
|
||||||
#: templates/registration/registration_form.html:101
|
|
||||||
msgid "Register!"
|
msgid "Register!"
|
||||||
msgstr "Đăng ký!"
|
msgstr "Đăng ký!"
|
||||||
|
|
||||||
|
@ -5128,7 +5252,7 @@ msgstr "Đăng ký!"
|
||||||
#: templates/registration/totp_disable.html:45
|
#: templates/registration/totp_disable.html:45
|
||||||
#: templates/registration/totp_enable.html:83
|
#: templates/registration/totp_enable.html:83
|
||||||
msgid "Enter the 6-digit code generated by your app:"
|
msgid "Enter the 6-digit code generated by your app:"
|
||||||
msgstr ""
|
msgstr "Nhập mã xác thực gồm 6 chữ số từ app bạn chọn"
|
||||||
|
|
||||||
#: templates/registration/totp_auth.html:41
|
#: templates/registration/totp_auth.html:41
|
||||||
#, python-format
|
#, python-format
|
||||||
|
@ -5516,43 +5640,51 @@ msgstr "Top Score"
|
||||||
msgid "Rank"
|
msgid "Rank"
|
||||||
msgstr "Rank"
|
msgstr "Rank"
|
||||||
|
|
||||||
#: templates/user/edit-profile.html:104
|
#: templates/user/edit-profile.html:111
|
||||||
msgid "Avatar"
|
|
||||||
msgstr "Ảnh đại diện"
|
|
||||||
|
|
||||||
#: templates/user/edit-profile.html:110
|
|
||||||
msgid "Self-description"
|
|
||||||
msgstr "Tự giới thiệu"
|
|
||||||
|
|
||||||
#: templates/user/edit-profile.html:118
|
|
||||||
msgid "Select your closest major city"
|
|
||||||
msgstr "Chọn thành phố gần nhất"
|
|
||||||
|
|
||||||
#: templates/user/edit-profile.html:127
|
|
||||||
msgid "Editor theme"
|
|
||||||
msgstr "Giao diện cho code editor"
|
|
||||||
|
|
||||||
#: templates/user/edit-profile.html:132
|
|
||||||
msgid "Math engine"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: templates/user/edit-profile.html:139
|
|
||||||
msgid "Change your password"
|
msgid "Change your password"
|
||||||
msgstr "Đổi mật khẩu"
|
msgstr "Đổi mật khẩu"
|
||||||
|
|
||||||
#: templates/user/edit-profile.html:150
|
#: templates/user/edit-profile.html:125
|
||||||
|
msgid "Avatar"
|
||||||
|
msgstr "Ảnh đại diện"
|
||||||
|
|
||||||
|
#: templates/user/edit-profile.html:131
|
||||||
|
msgid "Self-description"
|
||||||
|
msgstr "Tự giới thiệu"
|
||||||
|
|
||||||
|
#: templates/user/edit-profile.html:139
|
||||||
|
msgid "Select your closest major city"
|
||||||
|
msgstr "Chọn thành phố gần nhất"
|
||||||
|
|
||||||
|
#: templates/user/edit-profile.html:148
|
||||||
|
msgid "Editor theme"
|
||||||
|
msgstr "Giao diện cho code editor"
|
||||||
|
|
||||||
|
#: templates/user/edit-profile.html:153
|
||||||
|
msgid "Math engine"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates/user/edit-profile.html:164
|
||||||
msgid "Two Factor Authentication is enabled."
|
msgid "Two Factor Authentication is enabled."
|
||||||
msgstr "Two Factor Authentication đã được kích hoạt."
|
msgstr "Two Factor Authentication đã được kích hoạt."
|
||||||
|
|
||||||
#: templates/user/edit-profile.html:157
|
#: templates/user/edit-profile.html:168
|
||||||
msgid "Two Factor Authentication is disabled."
|
msgid "Disable"
|
||||||
msgstr "Two Factor Authentication đã được hủy kích hoạt."
|
msgstr "Tắt"
|
||||||
|
|
||||||
#: templates/user/edit-profile.html:162
|
#: templates/user/edit-profile.html:171
|
||||||
|
msgid "Two Factor Authentication is disabled."
|
||||||
|
msgstr "Two Factor Authentication chưa kích hoạt."
|
||||||
|
|
||||||
|
#: templates/user/edit-profile.html:172
|
||||||
|
msgid "Enable"
|
||||||
|
msgstr "Bật"
|
||||||
|
|
||||||
|
#: templates/user/edit-profile.html:176
|
||||||
msgid "User-script"
|
msgid "User-script"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/user/edit-profile.html:166
|
#: templates/user/edit-profile.html:180
|
||||||
msgid "Update profile"
|
msgid "Update profile"
|
||||||
msgstr "Cập nhật thông tin"
|
msgstr "Cập nhật thông tin"
|
||||||
|
|
||||||
|
@ -5768,6 +5900,15 @@ msgstr "Thông tin"
|
||||||
msgid "Check all"
|
msgid "Check all"
|
||||||
msgstr "Chọn tất cả"
|
msgstr "Chọn tất cả"
|
||||||
|
|
||||||
|
#~ msgid "Affiliated organizations"
|
||||||
|
#~ msgstr "Tổ chức bạn muốn tham gia"
|
||||||
|
|
||||||
|
#~ msgid "By registering, you agree to our"
|
||||||
|
#~ msgstr "Bạn đồng ý với"
|
||||||
|
|
||||||
|
#~ msgid "Terms & Conditions"
|
||||||
|
#~ msgstr "Điều khoản của chúng tôi"
|
||||||
|
|
||||||
#~ msgid "Change your avatar"
|
#~ msgid "Change your avatar"
|
||||||
#~ msgstr "Đổi ảnh đại diện"
|
#~ msgstr "Đổi ảnh đại diện"
|
||||||
|
|
||||||
|
@ -5875,9 +6016,6 @@ msgstr "Chọn tất cả"
|
||||||
#~ msgid "Color theme"
|
#~ msgid "Color theme"
|
||||||
#~ msgstr "Chủ đề màu sắc"
|
#~ msgstr "Chủ đề màu sắc"
|
||||||
|
|
||||||
#~ msgid "Change color theme"
|
|
||||||
#~ msgstr "Đổi chủ đề màu sắc"
|
|
||||||
|
|
||||||
#~ msgid "commented on {time}"
|
#~ msgid "commented on {time}"
|
||||||
#~ msgstr "bình luận vào {time}"
|
#~ msgstr "bình luận vào {time}"
|
||||||
|
|
||||||
|
|
21
templates/email_change/email_change.html
Normal file
21
templates/email_change/email_change.html
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
{% extends "base.html" %}
|
||||||
|
|
||||||
|
{% block media %}
|
||||||
|
<style type="text/css">
|
||||||
|
.errorlist {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
list-style: none;
|
||||||
|
color: red;
|
||||||
|
font-size: 0.8em;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block body %}
|
||||||
|
<form action="" method="post" class="form-area">{% csrf_token %}
|
||||||
|
<table border="0">{{ form.as_table() }}</table>
|
||||||
|
<hr>
|
||||||
|
<button style="float:right;" type="submit">{{ _('Verify Email') }}</button>
|
||||||
|
</form>
|
||||||
|
{% endblock %}
|
4
templates/email_change/email_change_failure.html
Normal file
4
templates/email_change/email_change_failure.html
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
{% extends "base.html" %}
|
||||||
|
{% block body %}
|
||||||
|
<p>{{ _('Invalid reset link.') }}</p>
|
||||||
|
{% endblock %}
|
6
templates/email_change/email_change_pending.html
Normal file
6
templates/email_change/email_change_pending.html
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
{% extends "base.html" %}
|
||||||
|
{% block body %}
|
||||||
|
{% if request.profile.email_change_pending %}
|
||||||
|
<p>{{ _('An email was sent to') }} {{request.profile.email_change_pending}}. {{_('If you don\'t see it, kindly check your spam folder as well.')}}</p>
|
||||||
|
{% endif %}
|
||||||
|
{% endblock %}
|
4
templates/email_change/email_change_success.html
Normal file
4
templates/email_change/email_change_success.html
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
{% extends "base.html" %}
|
||||||
|
{% block body %}
|
||||||
|
<p>{{ _('Your email was sucessfully changed to') }} {{user.email}}</p>
|
||||||
|
{% endblock %}
|
21
templates/general_email.html
Normal file
21
templates/general_email.html
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
font-family: Arial, sans-serif;
|
||||||
|
line-height: 1.6;
|
||||||
|
background-color: #f7f7f7;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<div style="max-width: 600px; margin: 0 auto; padding: 20px; background-color: #ffffff; box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);">
|
||||||
|
<div style="text-align: center; margin-bottom: 20px;">
|
||||||
|
<img src="{{ protocol }}://{{ domain }}{{static('icons/logo.png')}}" alt="{{site_name}}" style="max-width: 150px;">
|
||||||
|
</div>
|
||||||
|
<div style="margin-bottom: 20px; text-align: center;">
|
||||||
|
<h2>{{title}}</h2>
|
||||||
|
<p>{{_('Dear')}} {{username}},</p>
|
||||||
|
<p>{{message}}</p>
|
||||||
|
</div>
|
||||||
|
<div style="text-align: center;">
|
||||||
|
<a href="{{ protocol }}://{{ domain }}{{ url_path }}" style="display: inline-block; padding: 10px 20px; background-color: #007bff; color: #ffffff; text-decoration: none; border-radius: 4px;">{{button_text}}</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
|
@ -6,7 +6,7 @@
|
||||||
{% if show_preview %}
|
{% if show_preview %}
|
||||||
<div id="{{ postfix|safe }}-preview" data-preview-url="{{ preview_url }}" data-textarea-id="wmd-input-{{ postfix }}"
|
<div id="{{ postfix|safe }}-preview" data-preview-url="{{ preview_url }}" data-textarea-id="wmd-input-{{ postfix }}"
|
||||||
data-timeout="{{ preview_timeout or '' }}" class="wmd-panel wmd-preview dmmd-preview {{ extra_classes }}">
|
data-timeout="{{ preview_timeout or '' }}" class="wmd-panel wmd-preview dmmd-preview {{ extra_classes }}">
|
||||||
<div class="dmmd-preview-update"><i class="fa fa-refresh"></i> Update Preview</div>
|
<div class="dmmd-preview-update"><i class="fa fa-refresh"></i> {{_('Update Preview')}}</div>
|
||||||
<div class="dmmd-preview-content content-description"></div>
|
<div class="dmmd-preview-content content-description"></div>
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
|
@ -1,23 +1,16 @@
|
||||||
<b>Thanks for registering on the {{ site.name }}! We're glad to have you.</b>
|
{% set url_path = "/accounts/activate/" + activation_key %}
|
||||||
<br><br>
|
{% set title = _("Account activation") %}
|
||||||
The last step is activating your account. Please activate your {{ SITE_NAME }} account in the next {{ expiration_days }} days.
|
{% set message = _("Thanks for registering! We're glad to have you. The last step is activating your account. Please activate your account in the next %(expiration_days)d days.", expiration_days=expiration_days) %}
|
||||||
<br><br>
|
{% set username = user.get_username() %}
|
||||||
Please click on the following link to activate your account:
|
{% set button_text = _("Activate") %}
|
||||||
<p style="margin-left:1em">
|
{% set domain = site.domain %}
|
||||||
<a href="http://{{ site.domain }}/accounts/activate/{{ activation_key }}/">http://{{ site.domain }}/accounts/activate/{{ activation_key }}</a>
|
{% set protocol = "http" %}
|
||||||
</p>
|
{% include "general_email.html" %}
|
||||||
|
<br>
|
||||||
Alternatively, you can reply to this message to activate your account.
|
{{_("Alternatively, you can reply to this message to activate your account. Your reply must keep the following text intact for this to work:")}}
|
||||||
Your reply must keep the following text intact for this to work:
|
|
||||||
|
|
||||||
<pre style="margin-left:1em">
|
<pre style="margin-left:1em">
|
||||||
{{ activation_key }}
|
{{ activation_key }}
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
{% if SITE_ADMIN_EMAIL %}
|
{{_("See you soon!")}}
|
||||||
See you soon!
|
|
||||||
<br>
|
|
||||||
If you have problems activating your account, feel free to send us an email at <a href="mailto:{{ SITE_ADMIN_EMAIL }}">{{ SITE_ADMIN_EMAIL }}</a>.
|
|
||||||
{% else %}
|
|
||||||
See you soon!
|
|
||||||
{% endif %}
|
|
||||||
|
|
|
@ -1,19 +1,6 @@
|
||||||
<span style="display:block;margin: 0 2px;padding: 1em;border: 3px solid #FFDE05;background-color: #000;border-radius: 6px;font-size: .95em;color: #444;margin-bottom:0.75em">
|
{% set url_path = url('password_reset_confirm', uidb64=uid, token=token) %}
|
||||||
<div style="display:table;margin-left:2em"><img src="https://avatars1.githubusercontent.com/u/6934864?v=3&s=101" style="display:inline;vertical-align: middle">
|
{% set title = _("Password Reset") %}
|
||||||
<h1 style="font-size:4em;display:inline;vertical-align: middle"><a href="//{{ domain }}" style="text-decoration:none;color:gray"><span style="color: #FFDE05">LQD</span>OJ</a>
|
{% set message = _("We have received a request to reset your password. Click the button below to reset your password:") %}
|
||||||
</h1>
|
{% set username = user.get_username() %}
|
||||||
</div>
|
{% set button_text = _("Reset Password") %}
|
||||||
</span>
|
{% include "general_email.html" %}
|
||||||
<div style="display:block;margin: 0 2px;padding: 1em;border: 3px solid #2980B9;background-color: #f8f8f8;border-radius: 6px;font-size: .95em;color: #444;">
|
|
||||||
|
|
||||||
<b>Forgot your password on the {{ site_name }}? Don't worry!</b><br><br>
|
|
||||||
To reset the password for your account "{{ user.get_username() }}", click the below button.
|
|
||||||
<p align="center">
|
|
||||||
<a href="{{ protocol }}://{{ domain }}{{ url('password_reset_confirm', uidb64=uid, token=token) }}" style="cursor: pointer;display:block;text-align: center;padding: 4px 2px 5px;color: white;border: 1px solid #666;border-radius: 1px;background: #2980b9;background: linear-gradient(180deg, #00aee0, #2980b9);text-decoration: none;line-height:2em;font-size:1emm;width:12em;">Reset password</a>
|
|
||||||
</p>
|
|
||||||
{% if SITE_ADMIN_EMAIL %}
|
|
||||||
See you soon! If you have problems resetting your email, feel free to shoot us an email at <a href="mailto:{{ SITE_ADMIN_EMAIL }}">{{ SITE_ADMIN_EMAIL }}</a>
|
|
||||||
{% else %}
|
|
||||||
See you soon!
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
|
|
@ -1,4 +1,4 @@
|
||||||
{% extends "base.html" %}
|
{% extends "base.html" %}
|
||||||
{% block body %}
|
{% block body %}
|
||||||
<p>{{ _('You have successfully been registered. An email has been sent to the email address you provided to confirm your registration.') }}</p>
|
<p>{{ _('You have successfully been registered. An email has been sent to the email address you provided to confirm your registration. If you don\'t see it, kindly check your spam folder as well.') }}</p>
|
||||||
{% endblock %}
|
{% endblock %}
|
|
@ -78,12 +78,6 @@
|
||||||
<div class="block-header">{{ _('Default language') }}</div>
|
<div class="block-header">{{ _('Default language') }}</div>
|
||||||
<span class="fullwidth">{{ form.language }}</span>
|
<span class="fullwidth">{{ form.language }}</span>
|
||||||
|
|
||||||
<div class="block-header">{{ _('Affiliated organizations') }}</div>
|
|
||||||
{{ form.organizations }}
|
|
||||||
{% if form.organizations.errors %}
|
|
||||||
<div class="form-field-error">{{ form.organizations.errors }}</div>
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
{% if form.captcha %}
|
{% if form.captcha %}
|
||||||
<div style="margin-top: 0.5em">{{ form.captcha }}</div>
|
<div style="margin-top: 0.5em">{{ form.captcha }}</div>
|
||||||
{% if form.captcha.errors %}
|
{% if form.captcha.errors %}
|
||||||
|
@ -92,12 +86,6 @@
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
<hr>
|
<hr>
|
||||||
{% if tos_url %}
|
|
||||||
<span class="tos-section">
|
|
||||||
{{ _('By registering, you agree to our') }}
|
|
||||||
<a href="{{ tos_url }}">{{ _('Terms & Conditions') }}</a>.
|
|
||||||
</span>
|
|
||||||
{% endif %}
|
|
||||||
<button style="float:right;" type="submit">{{ _('Register!') }}</button>
|
<button style="float:right;" type="submit">{{ _('Register!') }}</button>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -47,6 +47,10 @@
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.main-info tr td {
|
||||||
|
padding-bottom: 1em;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
|
@ -91,7 +95,7 @@
|
||||||
|
|
||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
|
|
||||||
<table class="block-header grayed">
|
<table class="block-header grayed main-info">
|
||||||
<tr>
|
<tr>
|
||||||
<td> {{ _('Fullname') }}: </td>
|
<td> {{ _('Fullname') }}: </td>
|
||||||
<td> {{ form_user.first_name }} </td>
|
<td> {{ form_user.first_name }} </td>
|
||||||
|
@ -101,8 +105,25 @@
|
||||||
<td> {{ form_user.last_name }} </td>
|
<td> {{ form_user.last_name }} </td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td style="padding-top: 1em">{{ _('Avatar') }}: </td>
|
<td> {{ _('Password') }}: </td>
|
||||||
<td style="padding-top: 1em">{{ form.profile_image }}</td>
|
<td>
|
||||||
|
<a href="{{ url('password_change') }}">
|
||||||
|
{{ _('Change your password') }}
|
||||||
|
</a>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td> {{ _('Email') }}: </td>
|
||||||
|
<td>
|
||||||
|
{{ request.user.email }}
|
||||||
|
<a href="{{ url('email_change') }}">
|
||||||
|
({{ _('Change email') }})
|
||||||
|
</a>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>{{ _('Avatar') }}: </td>
|
||||||
|
<td>{{ form.profile_image }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
<hr>
|
<hr>
|
||||||
|
@ -133,29 +154,22 @@
|
||||||
<td><span class="fullwidth">{{ form.math_engine }}</span></td>
|
<td><span class="fullwidth">{{ form.math_engine }}</span></td>
|
||||||
</tr>
|
</tr>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<tr>
|
|
||||||
<td colspan="2">
|
|
||||||
<a href="{{ url('password_change') }}" class="inline-header">
|
|
||||||
{{ _('Change your password') }}
|
|
||||||
</a>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
</table>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
|
<br>
|
||||||
<div>
|
<div>
|
||||||
{% if profile.is_totp_enabled %}
|
{% if profile.is_totp_enabled %}
|
||||||
{{ _('Two Factor Authentication is enabled.') }}
|
{{ _('Two Factor Authentication is enabled.') }}
|
||||||
{% if require_staff_2fa and request.user.is_staff %}
|
{% if require_staff_2fa and request.user.is_staff %}
|
||||||
<a id="disable-2fa-button" class="button inline-button">Disable</a>
|
<a id="disable-2fa-button" class="button inline-button">Disable</a>
|
||||||
{% else %}
|
{% else %}
|
||||||
<a href="{{ url('disable_2fa') }}" class="button inline-button">Disable</a>
|
<a href="{{ url('disable_2fa') }}" class="button inline-button">{{_('Disable')}}</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% else %}
|
{% else %}
|
||||||
{{ _('Two Factor Authentication is disabled.') }}
|
{{ _('Two Factor Authentication is disabled.') }}
|
||||||
<a href="{{ url('enable_2fa') }}" class="button inline-button">Enable</a>
|
<a href="{{ url('enable_2fa') }}" class="button inline-button">{{_('Enable')}}</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
<br><hr>
|
<br><hr>
|
||||||
|
|
Loading…
Reference in a new issue