README.md changes and newsletter removal

This commit is contained in:
Tran Trong Nghia 2022-12-26 18:11:02 +07:00
parent 62a6f9f64c
commit ad85942c33
37 changed files with 4 additions and 467 deletions

View file

@ -30,11 +30,6 @@ Support plagiarism detection via [Stanford MOSS](https://theory.stanford.edu/~ai
Most of the setup are the same as DMOJ installations. You can view the installation guide of DMOJ here: https://docs.dmoj.ca/#/site/installation. Most of the setup are the same as DMOJ installations. You can view the installation guide of DMOJ here: https://docs.dmoj.ca/#/site/installation.
There is one minor change: Instead of `git clone https://github.com/DMOJ/site.git`, you clone this repo `git clone https://github.com/LQDJudge/online-judge.git`. There is one minor change: Instead of `git clone https://github.com/DMOJ/site.git`, you clone this repo `git clone https://github.com/LQDJudge/online-judge.git`.
### Additional Steps in Production:
1. To use newsletter (email sending), go to admin and create a newsletter.
2. Change the domain name and website name in Admin page: Navigation Bars/Sites
### Some frequent difficulties when installation: ### Some frequent difficulties when installation:
1. Missing the `local_settings.py`. You need to copy the `local_settings.py` in order to pass the check. 1. Missing the `local_settings.py`. You need to copy the `local_settings.py` in order to pass the check.
@ -100,7 +95,7 @@ Most of the steps are similar to Django tutorials. Here are two usual steps:
Leaderboard with information about contest rating, performance points and real name of all users. Leaderboard with information about contest rating, performance points and real name of all users.
![](https://i.imgur.com/ampxHXM.png) ![](https://i.imgur.com/SeUiXKQ.png)
### Admin dashboard ### Admin dashboard
@ -118,4 +113,4 @@ You can write the problems' statement in Markdown with LaTeX figures and formula
Users can communicate with each other and can see who's online. Users can communicate with each other and can see who's online.
![](https://i.imgur.com/y9SGCgl.png) ![](https://i.imgur.com/wvOjlLx.png)

View file

@ -98,7 +98,6 @@ MATHOID_CACHE_URL = False
TEXOID_GZIP = False TEXOID_GZIP = False
TEXOID_META_CACHE = "default" TEXOID_META_CACHE = "default"
TEXOID_META_CACHE_TTL = 86400 TEXOID_META_CACHE_TTL = 86400
DMOJ_NEWSLETTER_ID_ON_REGISTER = 1
BAD_MAIL_PROVIDERS = () BAD_MAIL_PROVIDERS = ()
BAD_MAIL_PROVIDER_REGEX = () BAD_MAIL_PROVIDER_REGEX = ()
@ -244,7 +243,6 @@ INSTALLED_APPS += (
"impersonate", "impersonate",
"django_jinja", "django_jinja",
"chat_box", "chat_box",
"newsletter",
"django.forms", "django.forms",
) )
@ -468,17 +466,6 @@ FILE_UPLOAD_PERMISSIONS = 0o644
MESSAGES_TO_LOAD = 15 MESSAGES_TO_LOAD = 15
NEWSLETTER_CONFIRM_EMAIL = False
# Amount of seconds to wait between each email. Here 100ms is used.
NEWSLETTER_EMAIL_DELAY = 0.1
# Amount of seconds to wait between each batch. Here one minute is used.
NEWSLETTER_BATCH_DELAY = 60
# Number of emails in one batch
NEWSLETTER_BATCH_SIZE = 100
ML_OUTPUT_PATH = None ML_OUTPUT_PATH = None
try: try:

View file

@ -1146,7 +1146,5 @@ handler404 = "judge.views.error.error404"
handler403 = "judge.views.error.error403" handler403 = "judge.views.error.error403"
handler500 = "judge.views.error.error500" handler500 = "judge.views.error.error500"
if "newsletter" in settings.INSTALLED_APPS:
urlpatterns.append(url(r"^newsletter/", include("newsletter.urls")))
if "impersonate" in settings.INSTALLED_APPS: if "impersonate" in settings.INSTALLED_APPS:
urlpatterns.append(url(r"^impersonate/", include("impersonate.urls"))) urlpatterns.append(url(r"^impersonate/", include("impersonate.urls")))

View file

@ -34,7 +34,7 @@ from judge.models import (
BlogPost, BlogPost,
ContestProblem, ContestProblem,
) )
from judge.utils.subscription import newsletter_id
from judge.widgets import ( from judge.widgets import (
HeavyPreviewPageDownWidget, HeavyPreviewPageDownWidget,
MathJaxPagedownWidget, MathJaxPagedownWidget,
@ -65,10 +65,6 @@ class UserForm(ModelForm):
class ProfileForm(ModelForm): class ProfileForm(ModelForm):
if newsletter_id is not None:
newsletter = forms.BooleanField(
label=_("Subscribe to contest updates"), initial=False, required=False
)
test_site = forms.BooleanField( test_site = forms.BooleanField(
label=_("Enable experimental features"), initial=False, required=False label=_("Enable experimental features"), initial=False, required=False
) )

View file

@ -1,10 +0,0 @@
from django.conf import settings
if "newsletter" in settings.INSTALLED_APPS:
from newsletter.models import Subscription
else:
Subscription = None
newsletter_id = (
None if Subscription is None else settings.DMOJ_NEWSLETTER_ID_ON_REGISTER
)

View file

@ -17,7 +17,6 @@ from sortedm2m.forms import SortedMultipleChoiceField
from judge.models import Language, Organization, Profile, TIMEZONE from judge.models import Language, Organization, Profile, TIMEZONE
from judge.utils.recaptcha import ReCaptchaField, ReCaptchaWidget from judge.utils.recaptcha import ReCaptchaField, ReCaptchaWidget
from judge.utils.subscription import Subscription, newsletter_id
from judge.widgets import Select2MultipleWidget, Select2Widget from judge.widgets import Select2MultipleWidget, Select2Widget
valid_id = re.compile(r"^\w+$") valid_id = re.compile(r"^\w+$")
@ -51,11 +50,6 @@ class CustomRegistrationForm(RegistrationForm):
widget=Select2MultipleWidget(attrs={"style": "width:100%"}), widget=Select2MultipleWidget(attrs={"style": "width:100%"}),
) )
if newsletter_id is not None:
newsletter = forms.BooleanField(
label=_("Subscribe to newsletter?"), initial=True, required=False
)
if ReCaptchaField is not None: if ReCaptchaField is not None:
captcha = ReCaptchaField(widget=ReCaptchaWidget()) captcha = ReCaptchaField(widget=ReCaptchaWidget())
@ -124,9 +118,6 @@ class RegistrationView(OldRegistrationView):
profile.language = cleaned_data["language"] profile.language = cleaned_data["language"]
profile.organizations.add(*cleaned_data["organizations"]) profile.organizations.add(*cleaned_data["organizations"])
profile.save() profile.save()
#if newsletter_id is not None and cleaned_data["newsletter"]:
# Subscription(user=user, newsletter_id=newsletter_id, subscribed=True).save()
return user return user
def get_initial(self, *args, **kwargs): def get_initial(self, *args, **kwargs):

View file

@ -35,14 +35,13 @@ from django.views.generic import DetailView, ListView, TemplateView
from django.template.loader import render_to_string from django.template.loader import render_to_string
from reversion import revisions from reversion import revisions
from judge.forms import UserForm, ProfileForm, newsletter_id from judge.forms import UserForm, ProfileForm
from judge.models import Profile, Rating, Submission, Friend from judge.models import Profile, Rating, Submission, Friend
from judge.performance_points import get_pp_breakdown from judge.performance_points import get_pp_breakdown
from judge.ratings import rating_class, rating_progress from judge.ratings import rating_class, rating_progress
from judge.tasks import import_users from judge.tasks import import_users
from judge.utils.problems import contest_completed_ids, user_completed_ids from judge.utils.problems import contest_completed_ids, user_completed_ids
from judge.utils.ranker import ranker from judge.utils.ranker import ranker
from judge.utils.subscription import Subscription
from judge.utils.unicode import utf8text from judge.utils.unicode import utf8text
from judge.utils.views import ( from judge.utils.views import (
DiggPaginatorMixin, DiggPaginatorMixin,
@ -416,26 +415,6 @@ def edit_profile(request):
revisions.set_user(request.user) revisions.set_user(request.user)
revisions.set_comment(_("Updated on site")) revisions.set_comment(_("Updated on site"))
if newsletter_id is not None:
try:
subscription = Subscription.objects.get(
user=request.user, newsletter_id=newsletter_id
)
except Subscription.DoesNotExist:
if form.cleaned_data["newsletter"]:
Subscription(
user=request.user,
newsletter_id=newsletter_id,
subscribed=True,
).save()
else:
if subscription.subscribed != form.cleaned_data["newsletter"]:
subscription.update(
("unsubscribe", "subscribe")[
form.cleaned_data["newsletter"]
]
)
perm = Permission.objects.get( perm = Permission.objects.get(
codename="test_site", codename="test_site",
content_type=ContentType.objects.get_for_model(Profile), content_type=ContentType.objects.get_for_model(Profile),
@ -449,15 +428,6 @@ def edit_profile(request):
else: else:
form_user = UserForm(instance=request.user) form_user = UserForm(instance=request.user)
form = ProfileForm(instance=profile, user=request.user) form = ProfileForm(instance=profile, user=request.user)
if newsletter_id is not None:
try:
subscription = Subscription.objects.get(
user=request.user, newsletter_id=newsletter_id
)
except Subscription.DoesNotExist:
form.fields["newsletter"].initial = False
else:
form.fields["newsletter"].initial = subscription.subscribed
form.fields["test_site"].initial = request.user.has_perm("judge.test_site") form.fields["test_site"].initial = request.user.has_perm("judge.test_site")
tzmap = settings.TIMEZONE_MAP tzmap = settings.TIMEZONE_MAP

View file

@ -30,7 +30,6 @@ packaging
celery celery
ansi2html @ git+https://github.com/DMOJ/ansi2html.git ansi2html @ git+https://github.com/DMOJ/ansi2html.git
sqlparse sqlparse
django-newsletter
netaddr netaddr
redis redis
lupa lupa

View file

@ -1,16 +0,0 @@
<?xml version="1.0"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>{% block title %}{{ _('Newsletter') }}{% endblock title %}</title>
<meta http-equiv="Content-type" content="text/html;charset=UTF-8" >
{% block header %}
{% endblock header %}
</head>
<body>
{% block body %}
{% endblock body %}
</body>
</html>

View file

@ -1,22 +0,0 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>{{ newsletter.title }}: {{ message.title }}</title>
</head>
<body>
{% for article in message.articles.all() %}
<div>{{ article.text|safe }}</div>
{% if article.url %}
<div><a href="{{ article.url }}">Read more</a></div>
{% endif %}
{% endfor %}
<a href="http://{{ site.domain }}{{ url('newsletter_unsubscribe_request', newsletter.slug) }}" style="color:#999;float:right">Unsubscribe</a>
{% if submission and submission.publish %}
<a href="http://{{ site.domain }}{{ submission.get_absolute_url }}" style="color:#999">Read message online</a>
{% endif %}
</body>
</html>

View file

@ -1,15 +0,0 @@
++++++++++++++++++++
{{ newsletter.title|safe }}: {{ message.title|safe }}
++++++++++++++++++++
{% for article in message.articles.all() %}
{{ article.title|safe }}
{{ article.text|striptags|safe }}
{% endfor %}
++++++++++++++++++++
Unsubscribe: http://{{ site }}{{ url('newsletter_unsubscribe_request', newsletter.slug) }}

View file

@ -1 +0,0 @@
{{ message.title|safe }}

View file

@ -1,20 +0,0 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd">
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Subscription to {{ newsletter.title }}</title>
</head>
<body>
Dear {{ subscription.name }},
you, or someone in your name requested a subscription to {{ newsletter.title }}.
If you would like to confirm your subscription, please follow this activation link:
http://{{ site.domain }}{{ subscription.subscribe_activate_url }}
Kind regards,
{{ newsletter.sender }}
</body>
</html>

View file

@ -1,9 +0,0 @@
Dear {{ subscription.name|safe }},
you, or someone in your name requested a subscription to {{ newsletter.title|safe }}.
If you would like to confirm your subscription, please follow this activation link:
http://{{ site.domain }}{{ subscription.subscribe_activate_url }}
Kind regards,
{{ newsletter.sender|safe }}

View file

@ -1 +0,0 @@
{{ newsletter.title|safe }} - Confirm subscription

View file

@ -1,20 +0,0 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd">
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Unsubscription from {{ newsletter.title }}</title>
</head>
<body>
Dear {{ subscription.name }},
you, or someone in your name requested unsubscription from {{ newsletter.title }}.
If you would like to confirm your unsubscription, please follow this activation link:
http://{{ site.domain }}{{ subscription.unsubscribe_activate_url }}
Kind regards,
{{ newsletter.sender }}
</body>
</html>

View file

@ -1,9 +0,0 @@
Dear {{ subscription.name|safe }},
you, or someone in your name requested unsubscription from {{ newsletter.title|safe }}.
If you would like to confirm your unsubscription, please follow this activation link:
http://{{ site.domain }}{{ subscription.unsubscribe_activate_url }}
Kind regards,
{{ newsletter.sender|safe }}

View file

@ -1 +0,0 @@
{{ newsletter.title|safe }} - Confirm unsubscription

View file

@ -1,20 +0,0 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd">
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Update of subscription to {{ newsletter.title }}</title>
</head>
<body>
Dear {{ subscription.name }},
you, or someone in your name requested updating your personal information for {{ newsletter.title }}.
To make changes to your information in our database, please follow this activation link:
http://{{ site.domain }}{{ subscription.update_activate_url }}
Kind regards,
{{ newsletter.sender }}
</body>
</html>

View file

@ -1,9 +0,0 @@
Dear {{ subscription.name|safe }},
you, or someone in your name requested updating your personal information for {{ newsletter.title|safe }}.
To make changes to your information in our database, please follow this activation link:
http://{{ site.domain }}{{ subscription.update_activate_url }}
Kind regards,
{{ newsletter.sender|safe }}

View file

@ -1 +0,0 @@
{{ newsletter.title|safe }} - Update information

View file

@ -1,13 +0,0 @@
{% extends "base.html" %}
{% block title %}{{ object.title }} - Newsletter - {{ SITE_LONG_NAME }}{% endblock %}
{% block content_title %}Newsletter: {{ object.title }}{% endblock %}
{% block body %}
<ul>
<li><a href="{{ url('newsletter_subscribe_request', object.slug) }}">Subscribe</a></li>
<li><a href="{{ url('newsletter_unsubscribe_request', object.slug) }}">Unsubscribe</a></li>
<li><a href="{{ url('newsletter_archive', object.slug) }}">Archive</a></li>
<li><a href="{{ url('newsletter_list') }}">Back to list</a></li>
</ul>
{% endblock %}

View file

@ -1,46 +0,0 @@
{% extends "base.html" %}
{% block title %} {{ _('Newsletter list') }} - {{ SITE_LONG_NAME }}{% endblock %}
{% block content_title %} {{ _('Newsletter list') }} {% endblock %}
{% block body %}
<h3> {{ _('Subscribe to get the latest emails about upcoming contests and events.')}} </h3>
<br/>
<div style="width: 50%; margin: auto;">
{% if request.user.is_authenticated %}
<form method="POST" action="" class="form-area" style="width:100%;">
{% csrf_token %}
{{ formset.management_form }}
<table class="table">
<tr>
<th>{{ _('Newsletter') }}</th>
<th>{{ _('Subscribe') }}</th>
</tr>
{% for form in formset.forms %}
<tr>
<td>{{ form.id }}
<a href="{{ url('newsletter_archive', form.instance.newsletter.slug) }}">
{{ form.instance.newsletter.title }}</a>
</td>
<td>{{ form.subscribed }}</d>
</tr>
{% endfor %}
</table>
<hr>
<p>
<input id="id_submit" name="submit" value="{{_('Update subscriptions')}}" type="submit" style="float: right">
</p>
</form>
{% else %}
<table class="form-area">
<tr>
<th>Newsletter</th>
</tr>
{% for newsletter in object_list %}
<tr>
<td><a href="{{ url('newsletter_detail', newsletter.slug) }}">{{ newsletter.title }}</a></td>
</tr>
{% endfor %}
</table>
{% endif %}
</div>
{% endblock %}

View file

@ -1,13 +0,0 @@
{% extends "base.html" %}
{% block title %}{{ newsletter }} - Newsletter Archive - {{ SITE_LONG_NAME }}{% endblock %}
{% block content_title %}Newsletter Archive: {{ newsletter }}{% endblock %}
{% block body %}
<ul>
{% for submission in latest %}
<li><a href="{{ submission.get_absolute_url() }}">{{ submission }}</a></li>
{% endfor %}
</ul>
<hr>
<p><a href="{{ url('newsletter_list') }}">Back to list</a></p>
{% endblock %}

View file

@ -1,12 +0,0 @@
{% extends "base.html" %}
{% block title %}Newsletter {{ newsletter.title }} {{ action }} activate{% endblock %}
{% block body %}
<h1>Newsletter {{ newsletter.title }} {{ action }} activate</h1>
<form enctype="multipart/form-data" method="post" action=".">
{% csrf_token %}
{{ form.as_p() }}
<p><input id="id_submit" name="submit" type="submit" value="Activate"></p>
</form>
{% endblock %}

View file

@ -1,19 +0,0 @@
{% extends "base.html" %}
{% block title %}Newsletter subscribe{% endblock %}
{% block body %}
<h1>Newsletter subscribe {{ newsletter.title }}</h1>
{% if error %}
<p>
Due to a technical error we were not able to submit your confirmation email.
This could be because your email address is invalid.
</p>
{% else %}
<form enctype="multipart/form-data" method="post" action=".">
{% csrf_token %}
{{ form.as_p() }}
<p><input id="id_submit" name="submit" value="Subscribe" type="submit"></p>
</form>
{% endif %}
{% endblock %}

View file

@ -1,7 +0,0 @@
{% extends "base.html" %}
{% block title %}Newsletter {{ newsletter.title }} {{ action }} activate{% endblock %}
{% block body %}
<h1>Newsletter {{ newsletter.title }} {{ action }} activate</h1>
<p>Your subscription has successfully been activated.</p>
{% endblock %}

View file

@ -1,8 +0,0 @@
{% extends "base.html" %}
{% block title %}Newsletter subscribe{% endblock %}
{% block body %}
<h1>Newsletter subscribe {{ newsletter.title }}</h1>
<p>Your subscription request was successfully received and an activation email has been sent to you. In that email
you will find a link which you need to follow in order to activate your subscription.</p>
{% endblock %}

View file

@ -1,22 +0,0 @@
{% extends "base.html" %}
{% block title %}Newsletter subscribe{% endblock %}
{% block body %}
<h1>Newsletter subscribe {{ newsletter.title }}</h1>
<p>Welcome, {{ request.user }}!</p>
{% if messages %}
<ul>
{% for message in messages %}
<li>{{ message }}</li>
{% endfor %}
</ul>
{% else %}
Do you want to subscribe to this newsletter?
<form enctype="multipart/form-data" method="post"
action="{{ url('newsletter_subscribe_confirm', newsletter.slug) }}">
{% csrf_token %}
<p><input id="id_submit" name="submit" value="Subscribe" type="submit"></p>
</form>
{% endif %}
{% endblock %}

View file

@ -1,17 +0,0 @@
{% extends "base.html" %}
{% block title %}Newsletter unsubscribe{% endblock %}
{% block body %}
<h1>Newsletter unsubscribe {{ newsletter.title }}</h1>
{% if error %}
<p>Due to a technical error we were not able to submit your confirmation email.
This could be because your email address is invalid.</p>
{% else %}
<form enctype="multipart/form-data" method="post" action=".">
{% csrf_token %}
{{ form.as_p() }}
<p><input id="id_submit" name="submit" value="Unsubscribe" type="submit"></p>
</form>
{% endif %}
{% endblock %}

View file

@ -1,9 +0,0 @@
{% extends "newsletter/common.html" %}
{% block title %}{{ _('Newsletter') }} {{ newsletter.title }} {{ action }} {{ _('activate') }}{% endblock title %}
{% block body %}
<h1>{{ _('Newsletter') }} {{ newsletter.title }} {{ action }} {{ _('activate') }}</h1>
<p>{{ _('You have successfully been unsubscribed.') }}</p>
{% endblock body %}

View file

@ -1,9 +0,0 @@
{% extends "newsletter/common.html" %}
{% block title %}{{ _('Newsletter unsubscribe') }}{% endblock title %}
{% block body %}
<h1>{{ _('Newsletter unsubscribe') }} {{ newsletter.title }}</h1>
<p>{{ _('Your unsubscription request has successfully been received. An email has been sent to you with a link you need to follow in order to confirm your unsubscription.') }}</p>
{% endblock body %}

View file

@ -1,25 +0,0 @@
{% extends "newsletter/common.html" %}
{% block title %}{{ _('Newsletter unsubscribe') }}{% endblock title %}
{% block body %}
<h1>{{ _('Newsletter unsubscribe') }} {{ newsletter.title }}</h1>
<p>Welcome, {{ request.user }}!</p>
{% if messages %}
<ul>
{% for message in messages %}
<li>{{ message }}</li>
{% endfor %}
</ul>
{% else %}
{{ _('Do you want to unsubscribe from this newsletter?') }}
<form enctype="multipart/form-data" method="post"
action="{{ url('newsletter_unsubscribe_confirm', newsletter.slug) }}">
{% csrf_token %}
<p><input id="id_submit" name="submit" value="{{ _('Unsubscribe') }}" type="submit"></p>
</form>
{% endif %}
{% endblock body %}

View file

@ -1,17 +0,0 @@
{% extends "newsletter/common.html" %}
{% block title %}{{ _('Newsletter update') }}{% endblock title %}
{% block body %}
<h1>{{ _('Newsletter update') }} {{ newsletter.title }}</h1>
{% if error %}
<p>{{ _('Due to a technical error we were not able to submit your confirmation email. This could be because your email address is invalid.') }}</p>
{% else %}
<form enctype="multipart/form-data" method="post" action=".">
{% csrf_token %}
{{ form.as_p() }}
<p><input id="id_submit" name="submit" value="{{ _('Update subscription') }}" type="submit"></p>
</form>
{% endif %}
{% endblock body %}

View file

@ -1,9 +0,0 @@
{% extends "newsletter/common.html" %}
{% block title %}{{ _('Newsletter') }} {{ newsletter.title }} {{ action }} {{ _('activate') }}{% endblock title %}
{% block body %}
<h1>{{ _('Newsletter') }} {{ newsletter.title }} {{ action }} {{ _('activate') }}</h1>
<p>{{ _('Your subscription has successfully been updated.') }}</p>
{% endblock body %}

View file

@ -1,9 +0,0 @@
{% extends "newsletter/common.html" %}
{% block title %}{{ _('Newsletter update') }}{% endblock title %}
{% block body %}
<h1>{{ _('Newsletter update') }} {{ newsletter.title }}</h1>
<p>{{ _('Your update request was successfully received and an activation email has been sent to you. In that email you will find a link which you need to follow in order to update your subscription.') }}</p>
{% endblock body %}

View file

@ -127,16 +127,6 @@
<td><span class="fullwidth">{{ form.math_engine }}</span></td> <td><span class="fullwidth">{{ form.math_engine }}</span></td>
</tr> </tr>
{% endif %} {% endif %}
{% if form.newsletter %}
<tr>
<td colspan="2">
{{ form.newsletter }}
<label for="id_newsletter" style="float: unset" class="inline-header grayed">
{{- _('Notify me about upcoming contests') -}}
</label>
</td>
</tr>
{% endif %}
<tr> <tr>
<td colspan="2"> <td colspan="2">
{{ form.test_site }} {{ form.test_site }}