# coding=utf-8 import re from django import forms from django.conf import settings from django.contrib.auth.models import User from django.contrib.auth.password_validation import get_default_password_validators from django.forms import ChoiceField, ModelChoiceField from django.shortcuts import render from django.utils.translation import gettext, gettext_lazy as _ from registration.backends.default.views import ( ActivationView as OldActivationView, RegistrationView as OldRegistrationView, ) from registration.forms import RegistrationForm from sortedm2m.forms import SortedMultipleChoiceField from judge.models import Language, Organization, Profile, TIMEZONE from judge.utils.recaptcha import ReCaptchaField, ReCaptchaWidget from judge.utils.subscription import Subscription, newsletter_id from judge.widgets import Select2MultipleWidget, Select2Widget valid_id = re.compile(r"^\w+$") bad_mail_regex = list(map(re.compile, settings.BAD_MAIL_PROVIDER_REGEX)) class CustomRegistrationForm(RegistrationForm): username = forms.RegexField( regex=r"^\w+$", max_length=30, label=_("Username"), error_messages={ "invalid": _("A username must contain letters, " "numbers, or underscores") }, ) timezone = ChoiceField( label=_("Timezone"), choices=TIMEZONE, widget=Select2Widget(attrs={"style": "width:100%"}), ) language = ModelChoiceField( queryset=Language.objects.all(), label=_("Preferred language"), empty_label=None, 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 newsletter_id is not None: newsletter = forms.BooleanField( label=_("Subscribe to newsletter?"), initial=True, required=False ) if ReCaptchaField is not None: 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): if User.objects.filter(email=self.cleaned_data["email"]).exists(): raise forms.ValidationError( gettext( 'The email address "%s" is already taken. Only one registration ' "is allowed per address." ) % self.cleaned_data["email"] ) if "@" in self.cleaned_data["email"]: domain = self.cleaned_data["email"].split("@")[-1].lower() if domain in settings.BAD_MAIL_PROVIDERS or any( regex.match(domain) for regex in bad_mail_regex ): raise forms.ValidationError( gettext( "Your email provider is not allowed due to history of abuse. " "Please use a reputable email provider." ) ) return self.cleaned_data["email"] class RegistrationView(OldRegistrationView): title = _("Registration") form_class = CustomRegistrationForm template_name = "registration/registration_form.html" def get_context_data(self, **kwargs): if "title" not in kwargs: kwargs["title"] = self.title tzmap = settings.TIMEZONE_MAP kwargs["TIMEZONE_MAP"] = tzmap or "http://momentjs.com/static/img/world.png" kwargs["TIMEZONE_BG"] = settings.TIMEZONE_BG if tzmap else "#4E7CAD" kwargs["password_validators"] = get_default_password_validators() kwargs["tos_url"] = settings.TERMS_OF_SERVICE_URL return super(RegistrationView, self).get_context_data(**kwargs) def register(self, form): user = super(RegistrationView, self).register(form) profile, _ = Profile.objects.get_or_create( user=user, defaults={ "language": Language.get_default_language(), }, ) cleaned_data = form.cleaned_data profile.timezone = cleaned_data["timezone"] profile.language = cleaned_data["language"] profile.organizations.add(*cleaned_data["organizations"]) profile.save() if newsletter_id is not None and cleaned_data["newsletter"]: Subscription(user=user, newsletter_id=newsletter_id, subscribed=True).save() return user def get_initial(self, *args, **kwargs): initial = super(RegistrationView, self).get_initial(*args, **kwargs) initial["timezone"] = settings.DEFAULT_USER_TIME_ZONE initial["language"] = Language.objects.get(key=settings.DEFAULT_USER_LANGUAGE) return initial class ActivationView(OldActivationView): title = _("Registration") template_name = "registration/activate.html" def get_context_data(self, **kwargs): if "title" not in kwargs: kwargs["title"] = self.title return super(ActivationView, self).get_context_data(**kwargs) def social_auth_error(request): return render( request, "generic-message.html", { "title": gettext("Authentication failure"), "message": request.GET.get("message"), }, )