Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408
  1. import string
  2. import urlparse
  3. import random
  4. from django import forms
  5. from django.conf import settings
  6. from django.contrib.auth import forms as auth_forms
  7. from django.contrib.auth.forms import AuthenticationForm
  8. from django.contrib.auth.tokens import default_token_generator
  9. from django.contrib.sites.models import get_current_site
  10. from django.core import validators
  11. from django.core.exceptions import ObjectDoesNotExist
  12. from django.core.exceptions import ValidationError
  13. from django.db.models import get_model
  14. from django.utils.translation import ugettext_lazy as _
  15. from oscar.core.loading import get_profile_class, get_class
  16. from oscar.core.compat import get_user_model
  17. from oscar.apps.customer.utils import get_password_reset_url, normalise_email
  18. Dispatcher = get_class('customer.utils', 'Dispatcher')
  19. CommunicationEventType = get_model('customer', 'communicationeventtype')
  20. ProductAlert = get_model('customer', 'ProductAlert')
  21. User = get_user_model()
  22. def generate_username():
  23. uname = ''.join([random.choice(string.letters + string.digits + '_') for i in range(30)])
  24. try:
  25. User.objects.get(username=uname)
  26. return generate_username()
  27. except User.DoesNotExist:
  28. return uname
  29. class PasswordResetForm(auth_forms.PasswordResetForm):
  30. """
  31. This form takes the same structure as its parent from django.contrib.auth
  32. """
  33. communication_type_code = "PASSWORD_RESET"
  34. def save(self, domain_override=None,
  35. subject_template_name='registration/password_reset_subject.txt',
  36. email_template_name='registration/password_reset_email.html',
  37. use_https=False, token_generator=default_token_generator,
  38. from_email=None, request=None, **kwargs):
  39. """
  40. Generates a one-use only link for resetting password and sends to the
  41. user.
  42. """
  43. site = get_current_site(request)
  44. if domain_override is not None:
  45. site.domain = site.name = domain_override
  46. for user in self.users_cache:
  47. # Build reset url
  48. reset_url = "%s://%s%s" % (
  49. 'https' if use_https else 'http',
  50. site.domain,
  51. get_password_reset_url(user))
  52. ctx = {
  53. 'user': user,
  54. 'site': site,
  55. 'reset_url': reset_url}
  56. messages = CommunicationEventType.objects.get_and_render(
  57. code=self.communication_type_code, context=ctx)
  58. Dispatcher().dispatch_user_messages(user, messages)
  59. class EmailAuthenticationForm(AuthenticationForm):
  60. """
  61. Extends the standard django AuthenticationForm, to support 75 character
  62. usernames. 75 character usernames are needed to support the EmailOrUsername
  63. auth backend.
  64. """
  65. username = forms.EmailField(label=_('Email Address'))
  66. redirect_url = forms.CharField(
  67. widget=forms.HiddenInput, required=False)
  68. def __init__(self, host, *args, **kwargs):
  69. self.host = host
  70. super(EmailAuthenticationForm, self).__init__(*args, **kwargs)
  71. def clean_redirect_url(self):
  72. url = self.cleaned_data['redirect_url'].strip()
  73. if not url:
  74. return settings.LOGIN_REDIRECT_URL
  75. host = urlparse.urlparse(url)[1]
  76. if host and host != self.host:
  77. return settings.LOGIN_REDIRECT_URL
  78. return url
  79. class CommonPasswordValidator(validators.BaseValidator):
  80. # See http://www.smartplanet.com/blog/business-brains/top-20-most-common-passwords-of-all-time-revealed-8216123456-8216princess-8216qwerty/4519
  81. forbidden_passwords = [
  82. 'password',
  83. '1234',
  84. '12345'
  85. '123456',
  86. '123456y',
  87. '123456789',
  88. 'iloveyou',
  89. 'princess',
  90. 'monkey',
  91. 'rockyou',
  92. 'babygirl',
  93. 'monkey',
  94. 'qwerty',
  95. '654321',
  96. 'dragon',
  97. 'pussy',
  98. 'baseball',
  99. 'football',
  100. 'letmein',
  101. 'monkey',
  102. '696969',
  103. 'abc123',
  104. 'qwe123',
  105. 'qweasd',
  106. 'mustang',
  107. 'michael',
  108. 'shadow',
  109. 'master',
  110. 'jennifer',
  111. '111111',
  112. '2000',
  113. 'jordan',
  114. 'superman'
  115. 'harley'
  116. ]
  117. message = _("Please choose a less common password")
  118. code = 'password'
  119. def __init__(self, password_file=None):
  120. self.limit_value = password_file
  121. def clean(self, value):
  122. return value.strip()
  123. def compare(self, value, limit):
  124. return value in self.forbidden_passwords
  125. def get_forbidden_passwords(self):
  126. if self.limit_value is None:
  127. return self.forbidden_passwords
  128. class EmailUserCreationForm(forms.ModelForm):
  129. email = forms.EmailField(label=_('Email address'))
  130. password1 = forms.CharField(
  131. label=_('Password'), widget=forms.PasswordInput,
  132. validators=[validators.MinLengthValidator(6),
  133. CommonPasswordValidator()])
  134. password2 = forms.CharField(
  135. label=_('Confirm password'), widget=forms.PasswordInput)
  136. redirect_url = forms.CharField(
  137. widget=forms.HiddenInput, required=False)
  138. class Meta:
  139. model = User
  140. fields = ('email',)
  141. def __init__(self, host=None, *args, **kwargs):
  142. self.host = host
  143. super(EmailUserCreationForm, self).__init__(*args, **kwargs)
  144. def clean_email(self):
  145. email = normalise_email(self.cleaned_data['email'])
  146. if User._default_manager.filter(email=email).exists():
  147. raise forms.ValidationError(
  148. _("A user with that email address already exists."))
  149. return email
  150. def clean_password2(self):
  151. password1 = self.cleaned_data.get('password1', '')
  152. password2 = self.cleaned_data.get('password2', '')
  153. if password1 != password2:
  154. raise forms.ValidationError(
  155. _("The two password fields didn't match."))
  156. return password2
  157. def clean_redirect_url(self):
  158. url = self.cleaned_data['redirect_url'].strip()
  159. if not url:
  160. return settings.LOGIN_REDIRECT_URL
  161. host = urlparse.urlparse(url)[1]
  162. if host and self.host and host != self.host:
  163. return settings.LOGIN_REDIRECT_URL
  164. return url
  165. def save(self, commit=True):
  166. user = super(EmailUserCreationForm, self).save(commit=False)
  167. user.set_password(self.cleaned_data['password1'])
  168. if 'username' in [f.name for f in User._meta.fields]:
  169. user.username = generate_username()
  170. if commit:
  171. user.save()
  172. return user
  173. class OrderSearchForm(forms.Form):
  174. date_from = forms.DateField(required=False, label=_("From"))
  175. date_to = forms.DateField(required=False, label=_("To"))
  176. order_number = forms.CharField(required=False, label=_("Order number"))
  177. def clean(self):
  178. if self.is_valid() and not any([self.cleaned_data['date_from'],
  179. self.cleaned_data['date_to'],
  180. self.cleaned_data['order_number']]):
  181. raise forms.ValidationError(_("At least one field is required."))
  182. return super(OrderSearchForm, self).clean()
  183. def description(self):
  184. if not self.is_bound or not self.is_valid():
  185. return _('All orders')
  186. date_from = self.cleaned_data['date_from']
  187. date_to = self.cleaned_data['date_to']
  188. order_number = self.cleaned_data['order_number']
  189. desc = None
  190. if date_from and date_to:
  191. desc = _('Orders placed between %(date_from)s and %(date_to)s') % {
  192. 'date_from': date_from,
  193. 'date_to': date_to}
  194. elif date_from:
  195. desc = _('Orders placed since %s') % date_from
  196. elif date_to:
  197. desc = _('Orders placed until %s') % date_to
  198. if order_number and desc is None:
  199. desc = _('Orders with order number containing %s') % order_number
  200. elif order_number and desc is not None:
  201. desc += _(' and order number containing %s') % order_number
  202. return desc
  203. def get_filters(self):
  204. date_from = self.cleaned_data['date_from']
  205. date_to = self.cleaned_data['date_to']
  206. order_number = self.cleaned_data['order_number']
  207. kwargs = {}
  208. if date_from and date_to:
  209. kwargs['date_placed__range'] = [date_from, date_to]
  210. elif date_from and not date_to:
  211. kwargs['date_placed__gt'] = date_from
  212. elif not date_from and date_to:
  213. kwargs['date_placed__lt'] = date_to
  214. if order_number:
  215. kwargs['number__contains'] = order_number
  216. return kwargs
  217. class UserForm(forms.ModelForm):
  218. def __init__(self, user, *args, **kwargs):
  219. self.user = user
  220. kwargs['instance'] = user
  221. super(UserForm, self).__init__(*args, **kwargs)
  222. if 'email' in self.fields:
  223. self.fields['email'].required = True
  224. def clean_email(self):
  225. """
  226. Make sure that the email address is aways unique as it is
  227. used instead of the username. This is necessary because the
  228. unique-ness of email addresses is *not* enforced on the model
  229. level in ``django.contrib.auth.models.User``.
  230. """
  231. email = normalise_email(self.cleaned_data['email'])
  232. if User._default_manager.filter(
  233. email=email).exclude(id=self.user.id).exists():
  234. raise ValidationError(
  235. _("A user with this email address already exists"))
  236. return email
  237. class Meta:
  238. model = User
  239. exclude = ('username', 'password', 'is_staff', 'is_superuser',
  240. 'is_active', 'last_login', 'date_joined',
  241. 'user_permissions', 'groups')
  242. Profile = get_profile_class()
  243. if Profile:
  244. class UserAndProfileForm(forms.ModelForm):
  245. email = forms.EmailField(label=_('Email address'), required=True)
  246. def __init__(self, user, *args, **kwargs):
  247. self.user = user
  248. try:
  249. instance = Profile.objects.get(user=user)
  250. except ObjectDoesNotExist:
  251. # User has no profile, try a blank one
  252. instance = Profile(user=user)
  253. kwargs['instance'] = instance
  254. super(UserAndProfileForm, self).__init__(*args, **kwargs)
  255. # Get a list of profile fields to help with ordering later
  256. profile_field_names = self.fields.keys()
  257. del profile_field_names[profile_field_names.index('email')]
  258. self.fields['email'].initial = self.instance.user.email
  259. # Add user fields (we look for core user fields first)
  260. core_field_names = set([f.name for f in User._meta.fields])
  261. user_field_names = ['email']
  262. for field_name in ('first_name', 'last_name'):
  263. if field_name in core_field_names:
  264. user_field_names.append(field_name)
  265. user_field_names.extend(User._meta.additional_fields)
  266. # Store user fields so we know what to save later
  267. self.user_field_names = user_field_names
  268. # Add additional user fields
  269. additional_fields = forms.fields_for_model(
  270. User, fields=user_field_names)
  271. self.fields.update(additional_fields)
  272. # Set initial values
  273. for field_name in user_field_names:
  274. self.fields[field_name].initial = getattr(user, field_name)
  275. # Ensure order of fields is email, user fields then profile fields
  276. self.fields.keyOrder = user_field_names + profile_field_names
  277. class Meta:
  278. model = Profile
  279. exclude = ('user',)
  280. def clean_email(self):
  281. email = normalise_email(self.cleaned_data['email'])
  282. if User._default_manager.filter(
  283. email=email).exclude(id=self.user.id).exists():
  284. raise ValidationError(
  285. _("A user with this email address already exists"))
  286. return email
  287. def save(self, *args, **kwargs):
  288. user = self.instance.user
  289. # Save user also
  290. for field_name in self.user_field_names:
  291. setattr(user, field_name, self.cleaned_data[field_name])
  292. user.save()
  293. return super(ProfileForm, self).save(*args, **kwargs)
  294. ProfileForm = UserAndProfileForm
  295. else:
  296. ProfileForm = UserForm
  297. class ProductAlertForm(forms.ModelForm):
  298. email = forms.EmailField(required=True, label=_(u'Send notification to'),
  299. widget=forms.TextInput(attrs={
  300. 'placeholder': _('Enter your email')
  301. }))
  302. def __init__(self, user, product, *args, **kwargs):
  303. self.user = user
  304. self.product = product
  305. super(ProductAlertForm, self).__init__(*args, **kwargs)
  306. # Only show email field to unauthenticated users
  307. if user and user.is_authenticated():
  308. self.fields['email'].widget = forms.HiddenInput()
  309. self.fields['email'].required = False
  310. def save(self, commit=True):
  311. alert = super(ProductAlertForm, self).save(commit=False)
  312. if self.user.is_authenticated():
  313. alert.user = self.user
  314. alert.product = self.product
  315. if commit:
  316. alert.save()
  317. return alert
  318. def clean(self):
  319. cleaned_data = self.cleaned_data
  320. email = cleaned_data.get('email')
  321. if email:
  322. try:
  323. ProductAlert.objects.get(
  324. product=self.product, email=email,
  325. status=ProductAlert.ACTIVE)
  326. except ProductAlert.DoesNotExist:
  327. pass
  328. else:
  329. raise forms.ValidationError(_(
  330. "There is already an active stock alert for %s") % email)
  331. elif self.user.is_authenticated():
  332. try:
  333. ProductAlert.objects.get(product=self.product,
  334. user=self.user,
  335. status=ProductAlert.ACTIVE)
  336. except ProductAlert.DoesNotExist:
  337. pass
  338. else:
  339. raise forms.ValidationError(_(
  340. "You already have an active alert for this product"))
  341. return cleaned_data
  342. class Meta:
  343. model = ProductAlert
  344. exclude = ('user', 'key',
  345. 'status', 'date_confirmed', 'date_cancelled', 'date_closed',
  346. 'product')