from django import forms from django.utils.translation import gettext_lazy as _ from django.core.exceptions import ValidationError from pingcap_sso.models import User, SecurityCode from pingcap_sso.lib.points import ( AWARD_USER_BIND_PHONE, award_points_by_type ) from pingcap_sso.lib.sso import parse_signup_channel_from_url from pingcap_sso.lib.captcha import verify_captcha, enable_captcha from pingcap_sso.utils.requests import get_safe_redirect_uri, get_client_ip from pingcap_sso.utils.phone import is_virtual_phone from pingcap_sso.exceptions import CaptchaRequiredError from .phone import PhoneField class SignupForm(forms.Form): company = forms.CharField( required=True, strip=True, min_length=1, max_length=100 ) email = forms.EmailField( required=True ) phone = PhoneField(required=True) code = forms.CharField( max_length=6, min_length=6, required=True, strip=True ) redirect_to = forms.URLField(required=False) re_token_v3 = forms.CharField(required=False, strip=True) def __init__(self, request, *args, **kwargs): self.request = request self.raw_redirect_to = None super(SignupForm, self).__init__(*args, **kwargs) def clean_redirect_to(self): self.raw_redirect_to = self.cleaned_data['redirect_to'] return get_safe_redirect_uri(self.raw_redirect_to, self.request) def clean_phone(self): phone = self.cleaned_data.get('phone') if phone and is_virtual_phone(phone): raise ValidationError(_('currently does not support virtual carrier numbers')) return phone def clean_re_token_v3(self): re_token = self.cleaned_data.get('re_token_v3') return re_token def clean(self): if self._errors: return phone = self.cleaned_data.get('phone') sms_code = self.cleaned_data.get('code') if User.objects.filter(phone=phone).exists(): self.add_error('phone', _('already used')) return if not SecurityCode.check_code( phone, sms_code, SecurityCode.DELIVER_BY_PHONE, scene=SecurityCode.SCENE_SIGNUP, ip=get_client_ip(self.request), ): self.add_error('code', _('invalid security code')) return return self.cleaned_data def save(self): data = self.cleaned_data new_user = User( username=User.generate_random_username(), company_name=data['company'], phone=data['phone'], signup_email=data['email'], ) new_user.set_password(None) new_user.signup_source_url = self.raw_redirect_to[:500] new_user.signup_channel = parse_signup_channel_from_url(self.raw_redirect_to) new_user.save() award_points_by_type(new_user, AWARD_USER_BIND_PHONE) return new_user class SignupSendCodeForm(forms.Form): phone = PhoneField(required=True) captcha_key = forms.CharField(required=False) captcha_response = forms.CharField(required=False) re_token_v3 = forms.CharField(required=False, strip=True) def __init__(self, request, *args, **kwargs): self.request = request super(SignupSendCodeForm, self).__init__(*args, **kwargs) def clean_phone(self): phone = self.cleaned_data.get('phone') if phone and is_virtual_phone(phone): raise ValidationError(_('currently does not support virtual carrier numbers')) return phone def clean(self): if self._errors: return phone = self.cleaned_data.get('phone') captcha_key = self.cleaned_data.get('captcha_key') captcha_response = self.cleaned_data.get('captcha_response') # re_token_v3 = self.cleaned_data.get('re_token_v3') if User.objects.filter(phone=phone).exists(): self.add_error('phone', _('this phone has already been used')) return if enable_captcha(phone): if not (captcha_key and captcha_response): raise CaptchaRequiredError(_('captcha key and response are required')) if not verify_captcha(captcha_key, captcha_response): self.add_error('captcha_response', _('invalid captcha response')) return # if not pingcap_captcha.verify( # get_client_ip(self.request), # re_token_v3 # ): # self.add_error( # 're_token_v3', # _('man-machine check failed, please refresh page and try again later') # ) # return return self.cleaned_data def save(self): phone = self.cleaned_data.get('phone') SecurityCode.send_code( phone, SecurityCode.DELIVER_BY_PHONE, scene=SecurityCode.SCENE_SIGNUP, ip=get_client_ip(self.request), )