diff --git a/README.md b/README.md index 4230f3c..db34259 100644 --- a/README.md +++ b/README.md @@ -47,6 +47,9 @@ pip install -r requirements.txt ./manage.py shell -c "from django.contrib.auth import get_user_model; get_user_model().objects.create_superuser('vasya', '1@abc.net', 'promprog')" ./manage.py runserver ``` +Создать токен + +Указать почту и токен в окружении ## Read more - Zenpy: [http://docs.facetoe.com.au](http://docs.facetoe.com.au) diff --git a/access_controller/settings.py b/access_controller/settings.py index 91aed60..24c1abf 100644 --- a/access_controller/settings.py +++ b/access_controller/settings.py @@ -35,6 +35,7 @@ INSTALLED_APPS = [ 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', + 'django_registration', 'main', ] diff --git a/access_controller/urls.py b/access_controller/urls.py index 12b2b8c..9262d42 100644 --- a/access_controller/urls.py +++ b/access_controller/urls.py @@ -15,13 +15,15 @@ Including another URLconf """ from django.conf.urls.static import static from django.contrib import admin -from django.urls import path +from django.urls import path, include from access_controller import settings from main.views import * urlpatterns = [ - path('admin/', admin.site.urls), - path('profile/', profile_page, name="Profile"), + path('admin/', admin.site.urls, name='admin'), + path('register/', CustomRegistrationView.as_view(), name='registration'), + path('', include('django_registration.backends.one_step.urls')), + path('profile/', profile_page, name='profile'), ] urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT) diff --git a/main/extra_func.py b/main/extra_func.py index 6d74db6..8f850b8 100644 --- a/main/extra_func.py +++ b/main/extra_func.py @@ -1,14 +1,20 @@ +import os + +from zenpy import Zenpy +from zenpy.lib.exception import APIException + from main.models import UserProfile # Дополнительные функции -def set_and_get_username(UP: UserProfile): # TODO: Переделать с получением данных через API +def set_and_get_name(UP: UserProfile): # TODO: Переделать с получением данных через API """ - Функция устанавливает поле :class:`user.username` текущим именем в Zendesk + Функция устанавливает поле :class:`username` текущим именем в Zendesk :param UP: Объект профиля пользователя :type UP: :class:`main.models.UserProfile` :return: Имя пользователя + :rtype: :class:`str` """ return UP.user.username @@ -20,6 +26,7 @@ def set_and_get_email(UP: UserProfile): # TODO: Переделать с пол :param UP: Объект профиля пользователя :type UP: :class:`main.models.UserProfile` :return: Почта пользователя + :rtype: :class:`str` """ return UP.user.email @@ -31,6 +38,7 @@ def set_and_get_role(UP: UserProfile): # TODO: Переделать с полу :param UP: Объект профиля пользователя :type UP: :class:`main.models.UserProfile` :return: Роль пользователя + :rtype: :class:`str` """ return UP.role @@ -42,5 +50,52 @@ def load_and_get_image(UP: UserProfile): # TODO: Переделать с пол :param UP: Объект профиля пользователя :type UP: :class:`main.models.UserProfile` :return: Название изображения + :rtype: :class:`str` """ return UP.image.name + + +def check_user_exist(email: str) -> bool: + """ + Функция проверяет, существует ли пользователь + + :param email: Электронная почта пользователя + :type email: :class:`str + :return: True, если существует, иначе False + :rtype: :class:`bool' + """ + admin_creds = { + 'email': os.environ.get('Admin_email'), + 'subdomain': 'ngenix1612197338', + 'token': os.environ.get('Oauth_token'), + } + admin = Zenpy(**admin_creds) + zenpy_user = admin.search(email, type='user') + if zenpy_user: + return True + return False + + +def check_user_auth(email: str, password: str) -> bool: + """ + Функция проверяет, верны ли входные данные + + :param email: Электроная почта пользователя + :type email: :class:`str` + :param password: Пароль пользователя + :type password: :class:`str` + :return: True, если входные данные верны, иначе False + :raise APIException: исключение, вызываемое если пользователь не аутентифицирован + :rtype: :class:`bool` + """ + try: + creds = { + 'email': email, + 'subdomain': 'ngenix1612197338', + 'password': password, + } + user = Zenpy(**creds) + user.search(email, type='user') + except APIException: + return False + return True diff --git a/main/forms.py b/main/forms.py new file mode 100644 index 0000000..fcd8a7f --- /dev/null +++ b/main/forms.py @@ -0,0 +1,34 @@ +from django import forms +from django_registration.forms import RegistrationFormUniqueEmail + + +class CustomRegistrationForm(RegistrationFormUniqueEmail): + """ + Форма для регистрации :class:`django_registration.forms.RegistrationFormUniqueEmail` + с полем для ввода пароля от Zendesk аккаунта и с добавлением bootstrap-класса 'form-control' для всех полей + + :param password_zen: Поле для ввода пароля от Zendesk + :type password_zen: :class:`django.forms.CharField` + """ + password_zen = forms.CharField( + required=True, + label="Пароль от Zendesk аккаунта", + strip=False, + widget=forms.PasswordInput(attrs={ + 'class': 'form-control' + }) + ) + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + for visible in self.visible_fields(): + if visible.field.widget.attrs.get('class', False): + print(visible.field.widget.attrs['class'].find('form-control')) + if visible.field.widget.attrs['class'].find('form-control') < 0: + visible.field.widget.attrs['class'] += 'form-control' + else: + visible.field.widget.attrs['class'] = 'form-control' + + class Meta(RegistrationFormUniqueEmail.Meta): + fields = RegistrationFormUniqueEmail.Meta.fields + fields.insert(2, 'password_zen') diff --git a/main/migrations/0002_userprofile_name.py b/main/migrations/0002_userprofile_name.py new file mode 100644 index 0000000..1737da2 --- /dev/null +++ b/main/migrations/0002_userprofile_name.py @@ -0,0 +1,18 @@ +# Generated by Django 3.1.6 on 2021-02-08 16:15 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('main', '0001_initial'), + ] + + operations = [ + migrations.AddField( + model_name='userprofile', + name='name', + field=models.CharField(default='None', max_length=100), + ), + ] diff --git a/main/models.py b/main/models.py index 73fb9ce..96d04db 100644 --- a/main/models.py +++ b/main/models.py @@ -8,3 +8,4 @@ class UserProfile(models.Model): user = models.OneToOneField(to=User, on_delete=models.CASCADE) role = models.IntegerField() image = models.ImageField(upload_to='user_avatars') + name = models.CharField(default='None', max_length=100) diff --git a/main/templates/django_registration/registration_closed.html b/main/templates/django_registration/registration_closed.html new file mode 100644 index 0000000..4fffce6 --- /dev/null +++ b/main/templates/django_registration/registration_closed.html @@ -0,0 +1,15 @@ +{% extends 'base/base.html' %} +{% load static %} + +{% block title %} + Регистрация завершена +{% endblock %} + +{% block heading %} + Регистрация +{% endblock %} + +{% block content %} +
+

Нет пользователя с указаным адресом электронной почты, либо был введён неверный пароль

+{% endblock %} diff --git a/main/templates/django_registration/registration_complete.html b/main/templates/django_registration/registration_complete.html new file mode 100644 index 0000000..bb064bb --- /dev/null +++ b/main/templates/django_registration/registration_complete.html @@ -0,0 +1,14 @@ +{% extends 'base/base.html' %} + +{% block title %} + Регистрация завершена +{% endblock %} + +{% block heading %} + Регистрация +{% endblock %} + +{% block content %} +
+

Регистрация прошла успешно. Войти сейчас

+{% endblock %} diff --git a/main/templates/django_registration/registration_form.html b/main/templates/django_registration/registration_form.html new file mode 100644 index 0000000..c4bb388 --- /dev/null +++ b/main/templates/django_registration/registration_form.html @@ -0,0 +1,24 @@ +{% extends 'base/base.html' %} +{% load static %} + +{% block title %} + Регистрация +{% endblock %} + +{% block heading %} + Регистрация +{% endblock %} +{% block content %} +
+ {% csrf_token %} + {% for field in form %} + {{ field.label_tag }} + {{ field }} +
+ {% if field.errors %} + {{ field.errors }} + {% endif %} + {% endfor %} + +
+{% endblock %} diff --git a/main/views.py b/main/views.py index 39054cc..dfd4c48 100644 --- a/main/views.py +++ b/main/views.py @@ -1,10 +1,55 @@ -from django.shortcuts import render, redirect +from django.shortcuts import render +from django.urls import reverse_lazy -from main.extra_func import set_and_get_username, set_and_get_email, load_and_get_image, set_and_get_role +from main.extra_func import set_and_get_name, set_and_get_email, load_and_get_image, set_and_get_role, check_user_exist, \ + check_user_auth from main.models import UserProfile +from django.contrib.auth.models import User +from main.forms import CustomRegistrationForm +from django_registration.views import RegistrationView +from zenpy import Zenpy + + +class CustomRegistrationView(RegistrationView): + """ + Отображение и логика работы страницы регистрации пользователя + """ + form_class = CustomRegistrationForm + template_name = 'django_registration/registration_form.html' + success_url = reverse_lazy('django_registration_complete') + is_allowed = True + + def register(self, form): + if check_user_exist(form.data['email']) and check_user_auth(form.data['email'], form.data['password_zen']): + user = User.objects.create_user( + username=form.data['username'], + email=form.data['email'], + password=form.data['password1'] + ) + profile = UserProfile( + image='None.png', + user=user, + role=0, + ) + set_and_get_name(profile) + set_and_get_email(profile) + set_and_get_role(profile) + load_and_get_image(profile) + profile.save() + else: + self.is_allowed = False + + def get_success_url(self, request): + """ + Вовзращет url-адресс страницы, куда нужно перейти после успешной/неуспешной регистрации + Используется самой django-registration + """ + if self.is_allowed: + return reverse_lazy('django_registration_complete') + else: + return reverse_lazy('django_registration_disallowed') -# Create your views here. def profile_page(request): """ @@ -19,7 +64,7 @@ def profile_page(request): else: # TODO: Убрать после появления регистрации и авторизации, добавить login_required() UP = UserProfile.objects.get(user=1) context = { - 'name': set_and_get_username(UP), + 'name': set_and_get_name(UP), 'email': set_and_get_email(UP), 'role': set_and_get_role(UP), 'image_name': load_and_get_image(UP), diff --git a/requirements.txt b/requirements.txt index 2f0966d..f51fa7a 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,7 +1,9 @@ # Engine Django==3.1.6 Pillow==8.1.0 +zenpy~=2.0.24 # Documentation Sphinx==3.4.3 sphinx-rtd-theme==0.5.1 +