2014-11-06 13:33:34 -08:00
|
|
|
import re
|
|
|
|
import requests
|
2012-02-28 17:37:01 -08:00
|
|
|
from django import forms
|
|
|
|
from vendor.zebra.forms import StripePaymentForm
|
|
|
|
from django.utils.safestring import mark_safe
|
2013-01-03 10:33:22 -08:00
|
|
|
from django.contrib.auth import authenticate
|
2013-01-07 17:28:43 -08:00
|
|
|
from django.contrib.auth.models import User
|
2017-05-18 16:59:35 -07:00
|
|
|
from apps.profile.models import change_password, blank_authenticate, MGiftCode, MCustomStyling
|
2013-05-06 15:12:18 -07:00
|
|
|
from apps.social.models import MSocialProfile
|
2012-02-29 12:15:01 -08:00
|
|
|
|
2012-02-28 17:37:01 -08:00
|
|
|
PLANS = [
|
2013-03-14 21:40:14 -07:00
|
|
|
("newsblur-premium-12", mark_safe("$12 / year <span class='NB-small'>($1/month)</span>")),
|
2012-02-29 12:15:01 -08:00
|
|
|
("newsblur-premium-24", mark_safe("$24 / year <span class='NB-small'>($2/month)</span>")),
|
|
|
|
("newsblur-premium-36", mark_safe("$36 / year <span class='NB-small'>($3/month)</span>")),
|
2012-02-28 17:37:01 -08:00
|
|
|
]
|
|
|
|
|
|
|
|
class HorizRadioRenderer(forms.RadioSelect.renderer):
|
|
|
|
""" this overrides widget method to put radio buttons horizontally
|
|
|
|
instead of vertically.
|
|
|
|
"""
|
|
|
|
def render(self):
|
|
|
|
"""Outputs radios"""
|
|
|
|
choices = '\n'.join(['%s\n' % w for w in self])
|
|
|
|
return mark_safe('<div class="NB-stripe-plan-choice">%s</div>' % choices)
|
|
|
|
|
|
|
|
class StripePlusPaymentForm(StripePaymentForm):
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
|
|
email = kwargs.pop('email')
|
|
|
|
plan = kwargs.pop('plan', '')
|
|
|
|
super(StripePlusPaymentForm, self).__init__(*args, **kwargs)
|
|
|
|
self.fields['email'].initial = email
|
|
|
|
if plan:
|
2012-02-29 12:15:01 -08:00
|
|
|
self.fields['plan'].initial = plan
|
2012-02-28 17:37:01 -08:00
|
|
|
|
|
|
|
email = forms.EmailField(widget=forms.TextInput(attrs=dict(maxlength=75)),
|
|
|
|
label='Email address',
|
|
|
|
required=False)
|
|
|
|
plan = forms.ChoiceField(required=False, widget=forms.RadioSelect(renderer=HorizRadioRenderer),
|
|
|
|
choices=PLANS, label='Plan')
|
2013-01-03 10:33:22 -08:00
|
|
|
|
|
|
|
|
|
|
|
class DeleteAccountForm(forms.Form):
|
|
|
|
password = forms.CharField(widget=forms.PasswordInput(),
|
|
|
|
label="Confirm your password",
|
|
|
|
required=False)
|
|
|
|
confirm = forms.CharField(label="Type \"Delete\" to confirm",
|
|
|
|
widget=forms.TextInput(),
|
|
|
|
required=False)
|
|
|
|
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
|
|
self.user = kwargs.pop('user')
|
|
|
|
super(DeleteAccountForm, self).__init__(*args, **kwargs)
|
|
|
|
|
|
|
|
def clean_password(self):
|
|
|
|
user_auth = authenticate(username=self.user.username,
|
|
|
|
password=self.cleaned_data['password'])
|
2013-04-05 19:23:42 -07:00
|
|
|
if not user_auth:
|
|
|
|
user_auth = blank_authenticate(username=self.user.username)
|
|
|
|
|
2013-01-03 10:33:22 -08:00
|
|
|
if not user_auth:
|
|
|
|
raise forms.ValidationError('Your password doesn\'t match.')
|
|
|
|
|
2014-11-06 13:33:34 -08:00
|
|
|
return self.cleaned_data['password']
|
2013-01-03 10:33:22 -08:00
|
|
|
|
|
|
|
def clean_confirm(self):
|
|
|
|
if self.cleaned_data.get('confirm', "").lower() != "delete":
|
|
|
|
raise forms.ValidationError('Please type "DELETE" to confirm deletion.')
|
|
|
|
|
2014-11-06 13:33:34 -08:00
|
|
|
return self.cleaned_data['confirm']
|
2013-01-07 17:28:43 -08:00
|
|
|
|
|
|
|
class ForgotPasswordForm(forms.Form):
|
|
|
|
email = forms.CharField(widget=forms.TextInput(),
|
|
|
|
label="Your email address",
|
|
|
|
required=False)
|
|
|
|
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
|
|
super(ForgotPasswordForm, self).__init__(*args, **kwargs)
|
|
|
|
|
|
|
|
def clean_email(self):
|
|
|
|
if not self.cleaned_data['email']:
|
|
|
|
raise forms.ValidationError('Please enter in an email address.')
|
|
|
|
try:
|
|
|
|
User.objects.get(email__iexact=self.cleaned_data['email'])
|
|
|
|
except User.MultipleObjectsReturned:
|
|
|
|
pass
|
|
|
|
except User.DoesNotExist:
|
|
|
|
raise forms.ValidationError('No user has that email address.')
|
|
|
|
|
2014-11-06 13:33:34 -08:00
|
|
|
return self.cleaned_data['email']
|
2013-01-07 17:28:43 -08:00
|
|
|
|
|
|
|
class ForgotPasswordReturnForm(forms.Form):
|
|
|
|
password = forms.CharField(widget=forms.PasswordInput(),
|
|
|
|
label="Your new password",
|
|
|
|
required=False)
|
2013-05-06 15:12:18 -07:00
|
|
|
|
|
|
|
class AccountSettingsForm(forms.Form):
|
2020-06-11 11:45:50 -04:00
|
|
|
use_required_attribute = False
|
2013-05-06 15:12:18 -07:00
|
|
|
username = forms.RegexField(regex=r'^\w+$',
|
|
|
|
max_length=30,
|
|
|
|
widget=forms.TextInput(attrs={'class': 'NB-input'}),
|
|
|
|
label='username',
|
|
|
|
required=False,
|
|
|
|
error_messages={
|
|
|
|
'invalid': "Your username may only contain letters and numbers."
|
|
|
|
})
|
|
|
|
email = forms.EmailField(widget=forms.TextInput(attrs={'maxlength': 75, 'class': 'NB-input'}),
|
|
|
|
label='email address',
|
2013-05-13 18:03:17 -07:00
|
|
|
required=True,
|
|
|
|
error_messages={'required': 'Please enter an email.'})
|
2013-05-06 15:12:18 -07:00
|
|
|
new_password = forms.CharField(widget=forms.PasswordInput(attrs={'class': 'NB-input'}),
|
|
|
|
label='password',
|
|
|
|
required=False)
|
|
|
|
# error_messages={'required': 'Please enter a password.'})
|
|
|
|
old_password = forms.CharField(widget=forms.PasswordInput(attrs={'class': 'NB-input'}),
|
|
|
|
label='password',
|
|
|
|
required=False)
|
2017-05-18 16:59:35 -07:00
|
|
|
custom_js = forms.CharField(widget=forms.TextInput(attrs={'class': 'NB-input'}),
|
|
|
|
label='custom_js',
|
|
|
|
required=False)
|
|
|
|
custom_css = forms.CharField(widget=forms.TextInput(attrs={'class': 'NB-input'}),
|
|
|
|
label='custom_css',
|
|
|
|
required=False)
|
2013-05-06 15:12:18 -07:00
|
|
|
|
|
|
|
def __init__(self, user, *args, **kwargs):
|
|
|
|
self.user = user
|
|
|
|
super(AccountSettingsForm, self).__init__(*args, **kwargs)
|
|
|
|
|
|
|
|
def clean_username(self):
|
|
|
|
username = self.cleaned_data['username']
|
|
|
|
return username
|
|
|
|
|
|
|
|
def clean_password(self):
|
|
|
|
if not self.cleaned_data['password']:
|
|
|
|
return ""
|
|
|
|
return self.cleaned_data['password']
|
|
|
|
|
|
|
|
def clean_email(self):
|
|
|
|
return self.cleaned_data['email']
|
|
|
|
|
|
|
|
def clean(self):
|
|
|
|
username = self.cleaned_data.get('username', '')
|
|
|
|
new_password = self.cleaned_data.get('new_password', '')
|
|
|
|
old_password = self.cleaned_data.get('old_password', '')
|
|
|
|
email = self.cleaned_data.get('email', None)
|
|
|
|
|
|
|
|
if username and self.user.username != username:
|
|
|
|
try:
|
|
|
|
User.objects.get(username__iexact=username)
|
|
|
|
except User.DoesNotExist:
|
|
|
|
pass
|
|
|
|
else:
|
|
|
|
raise forms.ValidationError("This username is already taken. Try something different.")
|
|
|
|
|
|
|
|
if self.user.email != email:
|
|
|
|
if email and User.objects.filter(email__iexact=email).count():
|
|
|
|
raise forms.ValidationError("This email is already being used by another account. Try something different.")
|
|
|
|
|
|
|
|
if old_password or new_password:
|
|
|
|
code = change_password(self.user, old_password, new_password, only_check=True)
|
|
|
|
if code <= 0:
|
|
|
|
raise forms.ValidationError("Your old password is incorrect.")
|
|
|
|
|
|
|
|
return self.cleaned_data
|
|
|
|
|
|
|
|
def save(self, profile_callback=None):
|
|
|
|
username = self.cleaned_data['username']
|
|
|
|
new_password = self.cleaned_data.get('new_password', None)
|
|
|
|
old_password = self.cleaned_data.get('old_password', None)
|
|
|
|
email = self.cleaned_data.get('email', None)
|
2017-05-18 16:59:35 -07:00
|
|
|
custom_css = self.cleaned_data.get('custom_css', None)
|
|
|
|
custom_js = self.cleaned_data.get('custom_js', None)
|
2013-05-06 15:12:18 -07:00
|
|
|
|
|
|
|
if username and self.user.username != username:
|
|
|
|
change_password(self.user, self.user.username, username)
|
|
|
|
self.user.username = username
|
|
|
|
self.user.save()
|
|
|
|
social_profile = MSocialProfile.get_user(self.user.pk)
|
|
|
|
social_profile.username = username
|
|
|
|
social_profile.save()
|
|
|
|
|
|
|
|
|
|
|
|
if self.user.email != email:
|
|
|
|
self.user.email = email
|
|
|
|
self.user.save()
|
2019-04-14 18:47:02 -04:00
|
|
|
|
|
|
|
sp = MSocialProfile.get_user(self.user.pk)
|
|
|
|
sp.email = email
|
|
|
|
sp.save()
|
2013-05-06 15:12:18 -07:00
|
|
|
|
|
|
|
if old_password or new_password:
|
|
|
|
change_password(self.user, old_password, new_password)
|
|
|
|
|
2017-05-18 16:59:35 -07:00
|
|
|
MCustomStyling.save_user(self.user.pk, custom_css, custom_js)
|
|
|
|
|
2014-11-06 13:33:34 -08:00
|
|
|
class RedeemCodeForm(forms.Form):
|
2020-06-11 11:45:50 -04:00
|
|
|
use_required_attribute = False
|
2014-11-06 13:33:34 -08:00
|
|
|
gift_code = forms.CharField(widget=forms.TextInput(),
|
|
|
|
label="Gift code",
|
|
|
|
required=True)
|
|
|
|
|
|
|
|
def clean_gift_code(self):
|
|
|
|
gift_code = self.cleaned_data['gift_code']
|
|
|
|
|
2014-11-06 15:17:43 -08:00
|
|
|
gift_code = re.sub(r'[^a-zA-Z0-9]', '', gift_code).lower()
|
|
|
|
|
2014-11-06 13:33:34 -08:00
|
|
|
if len(gift_code) != 12:
|
|
|
|
raise forms.ValidationError('Your gift code should be 12 characters long.')
|
|
|
|
|
2015-06-30 16:05:58 -07:00
|
|
|
newsblur_gift_code = MGiftCode.objects.filter(gift_code__iexact=gift_code)
|
|
|
|
|
|
|
|
if newsblur_gift_code:
|
|
|
|
# Native gift codes
|
|
|
|
newsblur_gift_code = newsblur_gift_code[0]
|
|
|
|
return newsblur_gift_code.gift_code
|
|
|
|
else:
|
|
|
|
# Thinkup / Good Web Bundle
|
|
|
|
req = requests.get('https://www.thinkup.com/join/api/bundle/', params={'code': gift_code})
|
|
|
|
response = req.json()
|
2014-11-06 13:33:34 -08:00
|
|
|
|
2015-06-30 16:05:58 -07:00
|
|
|
is_valid = response.get('is_valid', None)
|
|
|
|
if is_valid:
|
|
|
|
return gift_code
|
|
|
|
elif is_valid == False:
|
|
|
|
raise forms.ValidationError('Your gift code is invalid. Check it for errors.')
|
|
|
|
elif response.get('error', None):
|
|
|
|
raise forms.ValidationError('Your gift code is invalid, says the server: %s' % response['error'])
|
2014-11-06 13:33:34 -08:00
|
|
|
|
|
|
|
return gift_code
|