diff --git a/accounts_ext/__init__.py b/accounts_ext/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/accounts_ext/admin.py b/accounts_ext/admin.py new file mode 100644 index 0000000..45eb74e --- /dev/null +++ b/accounts_ext/admin.py @@ -0,0 +1,26 @@ +from django.contrib import admin +from .models import Profile + +# def delete_model(modeladmin, request, queryset): +# for obj in queryset: +# user_profile = obj.user.profile +# if user_profile.user_points >= obj.points: +# user_profile.user_points -= obj.points +# user_profile.save() +# obj.delete() +# +# delete_model.short_description = "Удалить как исполненный" + +# class PickUpRequestAdmin(admin.ModelAdmin): +# list_display = [field.name for field in PickUpRequest._meta.fields] +# actions = [delete_model] +# class Meta: +# model = PickUpRequest +# +# class UserProfileAdmin(admin.ModelAdmin): +# list_display = [field.name for field in Profile._meta.fields] +# class Meta: +# model = Profile + +# admin.site.register(Profile, UserProfileAdmin) +# admin.site.register(PickUpRequest, PickUpRequestAdmin) diff --git a/accounts_ext/apps.py b/accounts_ext/apps.py new file mode 100644 index 0000000..c708551 --- /dev/null +++ b/accounts_ext/apps.py @@ -0,0 +1,7 @@ +from django.apps import AppConfig +from django.utils.translation import ugettext_lazy as _ + + +class AccountsExtConfig(AppConfig): + name = 'accounts_ext' + verbose_name = _("Authentication and Authorization") diff --git a/accounts_ext/forms.py b/accounts_ext/forms.py new file mode 100644 index 0000000..4bdc31d --- /dev/null +++ b/accounts_ext/forms.py @@ -0,0 +1,298 @@ +import logging +from captcha.fields import CaptchaField +from crispy_forms.helper import FormHelper +from crispy_forms.layout import Layout, Field, Div, Submit, HTML +from django import forms +from django.conf import settings +from django.contrib.auth import get_user_model, password_validation +from django.core.exceptions import ObjectDoesNotExist +from django.forms import inlineformset_factory +from django.urls import reverse, reverse_lazy +from django.utils.translation import ugettext_lazy as _ +from registration.forms import RegistrationFormUniqueEmail +from django.contrib.auth.forms import ( + AuthenticationForm as AuthenticationFormBase, + PasswordResetForm as PasswordResetFormBase, + PasswordChangeForm as PasswordChangeFormBase +) + +from core.models import STATUS_ACTIVE +from .models import User, Profile, Company + +logger = logging.getLogger(__name__) + + +# class PickUpPointsForm(layout.ModelForm): +# class Meta:' +# model = PickUpRequest +# fields = ('requisites',) + + +class RegistrationForm(RegistrationFormUniqueEmail): + email = forms.EmailField(label=_("E-mail"), widget=forms.EmailInput(attrs={'class': 'reg__text'})) + password1 = forms.CharField( + label=_('Пароль'), + strip=False, + widget=forms.PasswordInput(attrs={'class': 'reg__text-label'}), + help_text=password_validation.password_validators_help_text_html(), + ) + password2 = forms.CharField( + label=_('Подтверждение пароля'), + widget=forms.PasswordInput(attrs={'class': 'reg__text-label'}), + strip=False, + help_text=_('Для потверждения пароля введите его еще раз'), + ) + first_name = forms.CharField(label=_("Имя"), max_length=255, widget=forms.TextInput(attrs={'class': 'reg__text'})) + last_name = forms.CharField(label=_("Фамилия"), max_length=255, + widget=forms.TextInput(attrs={'class': 'reg__text'})) + patronymic = forms.CharField(label=_("Отчество"), max_length=255, + widget=forms.TextInput(attrs={'class': 'reg__text'})) + agreement = forms.BooleanField() + + captcha = CaptchaField(required=not settings.DEBUG) + + title = _('Регистрация') + + def save(self, commit=True): + user = super().save(commit) + profile = Profile.objects.filter(user=user).first() + if profile: + profile.first_name = self.cleaned_data.get('first_name') + profile.last_name = self.cleaned_data.get('last_name') + profile.patronymic = self.cleaned_data.get('patronymic') + profile.save() + else: + logger.error( + msg="User {user_email} missing profile object".format({'user_email': user.email}) + ) + return user + + class Meta: + model = User + fields = ('username',) + labels = { + 'username': _('Логин'), + } + help_texts = { + 'username': _('Не менее 5х символов'), + } + widgets = { + 'username': forms.TextInput(attrs={'class': 'reg__text-label'}), + } + + +class RegistrationCompanyForm(forms.ModelForm): + is_individual = forms.BooleanField(label=_('Я физическое лицо'), required=False) + + def save(self, user, commit=True): + self.instance.user = user + return super().save(commit) + + class Meta: + model = Company + fields = ('company_name', 'address', 'inn', 'ogrn') + labels = { + 'company_name': _('Наименование'), + 'inn': _('ИНН'), + 'ogrn': _('ОГРН'), + 'address': _('Юридический адрес') + } + widgets = { + 'company_name': forms.TextInput(attrs={'class': 'reg__text'}), + 'inn': forms.TextInput(attrs={'class': 'reg__text'}), + 'ogrn': forms.TextInput(attrs={'class': 'reg__text'}), + 'address': forms.Textarea(attrs={'class': 'reg__text', 'rows': 5, 'cols': 40}) + } + + +class AuthenticationForm(AuthenticationFormBase): + username = forms.CharField(max_length=255, widget=forms.TextInput(attrs={ + 'class': 'reg__text', + 'style': 'text-align:center', + 'placeholder': _('Логин') + })) + password = forms.CharField(max_length=255, widget=forms.PasswordInput(attrs={ + 'class': 'reg__text', + 'style': 'text-align:center', + 'placeholder': _('Пароль') + })) + + field_template = 'bootstrap/forms/authentication.html' + title = _('Вход') + + def __init__(self, *args, **kwargs): + self.helper = FormHelper() + self.helper.layout = Layout( + Field('username', template=self.field_template), + Field('password', template=self.field_template), + Div( + HTML('{}'.format( + reverse_lazy('accounts_ext:reset_password'), + _('Забыли пароль ?')) + ), + css_class="text-right" + ), + Div( + Div( + Submit('submit', _('Войти'), css_class='btn-danger'), + css_class='col-lg-12 text-center' + ), + css_class='row' + ), + ) + super().__init__(*args, **kwargs) + + +class PasswordResetRequestForm(PasswordResetFormBase): + field_template = 'bootstrap/forms/authentication.html' + + email_slug = 'reset_password' + title = _('Сброс пароля') + + def __init__(self, *args, **kwargs): + self.helper = FormHelper() + self.helper.form_action = reverse_lazy('accounts_ext:reset_password') + self.helper.layout = Layout( + Field('email', css_class='reg__text', template=self.field_template, placeholder="example@email.com"), + Div( + Div( + Submit('submit', _('Сбросить'), css_class='btn-danger'), + css_class='col-lg-12 text-center' + ), + css_class="row" + ), + ) + super().__init__(*args, **kwargs) + + def get_users(self, email): + active_users = get_user_model()._default_manager.filter(**{ + '%s__iexact' % get_user_model().get_email_field_name(): email, + 'status': STATUS_ACTIVE, + }) + return (u for u in active_users if u.has_usable_password()) + + def send_mail(self, subject_template_name, email_template_name, context, from_email, to_email, + html_email_template_name=None): + try: + # mail_template = MailTemplate.objects.filter(slug=self.email_slug).first() + kwargs = { + 'subject': subject_template_name, + # 'message': get_template(html_email_template_name).templatetags.source + } + if not kwargs: + kwargs = { + 'slug': self.email_slug, + 'name': email_template_name, + 'num_of_retries': 3, + 'is_html': True + } + # MailTemplate.objects.create(**kwargs) + else: + pass + # mail_template.subject = kwargs.get('subject', mail_template.subject) + # mail_template.message = kwargs.get('message', mail_template.message) + # mail_template.save() + user = User.active.filter(email__iexact=to_email).first() + first_name = user.profile.first_name or "" + last_name = user.profile.last_name or "" + full_name = first_name + ' ' + last_name + if len(full_name.strip()) != 0: + context.update({'username': full_name}) + # send_db_mail( + # self.email_slug, + # to_email, + # subject_template_name, + # context, + # from_email=from_email, + # retry=True, + # retry_delay=300, + # max_retries=3, + # send_at_date=datetime.now(), + # use_celery=celery_supported() + # ) + except ObjectDoesNotExist as e: + logger.critical(e) + + def clean(self): + return super().clean() + + +class PasswordResetForm(PasswordChangeFormBase): + field_template = 'bootstrap/field.html' + + field_order = ['new_password1', 'new_password2'] + + title = _('Сброс пароля') + + def __init__(self, *args, **kwargs): + self.request = kwargs.pop('request') + + self.helper = FormHelper() + self.helper.form_action = self.request.path + self.helper.layout = Layout( + Field('new_password1', template=self.field_template), + Field('new_password2', template=self.field_template), + Div( + Div( + Submit('submit', _('Сброс'), css_class='btn-danger'), + css_class='col-lg-12 text-center' + ), + css_class="row" + ), + ) + + super().__init__(kwargs.pop('user'), *args, **kwargs) + self.fields['new_password1'].help_text = self.fields['new_password1'].help_text.replace('