From 981e793e3e856eacdb4b0418c6fa42100319aa59 Mon Sep 17 00:00:00 2001 From: Sokurov Idar Date: Sat, 6 Feb 2021 14:33:55 +0300 Subject: [PATCH 01/18] Add profile page and temporary base.html --- access_controller/settings.py | 7 +---- access_controller/urls.py | 6 ++++ main/extra_func.py | 46 +++++++++++++++++++++++++++++++ main/templates/base/base.html | 35 +++++++++++++++++++++++ main/templates/pages/profile.html | 35 +++++++++++++++++++++++ main/views.py | 27 +++++++++++++++++- 6 files changed, 149 insertions(+), 7 deletions(-) create mode 100644 main/extra_func.py create mode 100644 main/templates/base/base.html create mode 100644 main/templates/pages/profile.html diff --git a/access_controller/settings.py b/access_controller/settings.py index dc44189..91aed60 100644 --- a/access_controller/settings.py +++ b/access_controller/settings.py @@ -15,7 +15,6 @@ from pathlib import Path # Build paths inside the project like this: BASE_DIR / 'subdir'. BASE_DIR = Path(__file__).resolve().parent.parent - # Quick-start development settings - unsuitable for production # See https://docs.djangoproject.com/en/3.1/howto/deployment/checklist/ @@ -27,7 +26,6 @@ DEBUG = True ALLOWED_HOSTS = [] - # Application definition INSTALLED_APPS = [ @@ -72,7 +70,6 @@ TEMPLATES = [ WSGI_APPLICATION = 'access_controller.wsgi.application' - # Database # https://docs.djangoproject.com/en/3.1/ref/settings/#databases @@ -83,7 +80,6 @@ DATABASES = { } } - # Password validation # https://docs.djangoproject.com/en/3.1/ref/settings/#auth-password-validators @@ -102,7 +98,6 @@ AUTH_PASSWORD_VALIDATORS = [ }, ] - # Internationalization # https://docs.djangoproject.com/en/3.1/topics/i18n/ @@ -116,7 +111,6 @@ USE_L10N = True USE_TZ = True - # Static files (CSS, JavaScript, Images) # https://docs.djangoproject.com/en/3.1/howto/static-files/ @@ -126,3 +120,4 @@ STATICFILES_DIRS = [ ] MEDIA_ROOT = BASE_DIR / 'media' +MEDIA_URL = '/media/' diff --git a/access_controller/urls.py b/access_controller/urls.py index e0ecf63..12b2b8c 100644 --- a/access_controller/urls.py +++ b/access_controller/urls.py @@ -13,9 +13,15 @@ Including another URLconf 1. Import the include() function: from django.urls import include, path 2. Add a URL to urlpatterns: path('blog/', include('blog.urls')) """ +from django.conf.urls.static import static from django.contrib import admin from django.urls import path +from access_controller import settings +from main.views import * + urlpatterns = [ path('admin/', admin.site.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 new file mode 100644 index 0000000..a5ca8d2 --- /dev/null +++ b/main/extra_func.py @@ -0,0 +1,46 @@ +from main.models import UserProfile + + +# Дополнительные функции +def set_and_get_username(UP: UserProfile): # TODO: Переделать с получением данных через API + """ + Функция устанавливает поле :class:`user.username` текущим именем в Zendesk + + :param UP: Объект профиля пользователя + :type UP: :class:`UserProfile` + :return: Имя пользователя + """ + return UP.user.username + + +def set_and_get_email(UP: UserProfile): # TODO: Переделать с получением данных через API + """ + Функция устанавливает поле :class:`user.email` текущей почтой в Zendesk + + :param UP: Объект профиля пользователя + :type UP: :class:`UserProfile` + :return: Почта пользователя + """ + return UP.user.email + + +def set_and_get_role(UP: UserProfile): # TODO: Переделать с получением данных через API + """ + Функция устанавливает поле :class:`role` текущей ролью в Zendesk + + :param UP: Объект профиля пользователя + :type UP: :class:`UserProfile` + :return: Роль пользователя + """ + return UP.role + + +def load_and_get_image(UP: UserProfile): # TODO: Переделать с получением изображения через API + """ + Функция загружает и устанавливает изображение в поле :class:`image` + + :param UP: Объект профиля пользователя + :type UP: :class:`UserProfile` + :return: Название изображения + """ + return UP.image.name diff --git a/main/templates/base/base.html b/main/templates/base/base.html new file mode 100644 index 0000000..b53080c --- /dev/null +++ b/main/templates/base/base.html @@ -0,0 +1,35 @@ + + + + + {% block title %}{% endblock %} + + + + + +
+
+

+ {% block heading %}{% endblock %} +

+
+ +
+ {% block content %}{% endblock %} +
+
+ + + diff --git a/main/templates/pages/profile.html b/main/templates/pages/profile.html new file mode 100644 index 0000000..c6c1780 --- /dev/null +++ b/main/templates/pages/profile.html @@ -0,0 +1,35 @@ +{% extends 'base/base.html' %} +{% load static %} + +{% block title %} + {{ pagename }} +{% endblock %} + +{% block heading %} + Профиль +{% endblock %} + +{% block extra_css%} + .img{ + width:auto; + height:auto; + max-width:400px!important; + max-height:500px!important; + } +{% endblock %} +{% block content %} +
+
+
+
+ Нет изображения
+
+
+
+

Имя пользователя {{name}}

+

Электронная почта {{email}}

+

Текущая роль {{role}}

+
+
+
+{% endblock %} diff --git a/main/views.py b/main/views.py index 91ea44a..19fe76c 100644 --- a/main/views.py +++ b/main/views.py @@ -1,3 +1,28 @@ -from django.shortcuts import render +from django.shortcuts import render, redirect + +from main.extra_func import set_and_get_username, set_and_get_email, load_and_get_image, set_and_get_role +from main.models import UserProfile + # Create your views here. + +def profile_page(request): + """ + Отображение страницы профиля + + :param request: объект с деталями запроса + :type request: :class:`django.http.HttpResponse + :return: объект ответа сервера с HTML-кодом внутри + """ + if request.user.is_authenticated: + UP = UserProfile.objects.get(user=request.user) + else: # TODO: Убрать после появления регистрации и авторизации, добавить login_required() + UP = UserProfile.objects.get(user=1) + context = { + 'name': set_and_get_username(UP), + 'email': set_and_get_email(UP), + 'role': set_and_get_role(UP), + 'image_name': load_and_get_image(UP), + 'pagename': 'Страница профиля' + } + return render(request, 'pages/profile.html', context) From 3d4a49a3500bf56b5be9918519e71583752f80be Mon Sep 17 00:00:00 2001 From: Sokurov Idar Date: Sat, 6 Feb 2021 14:45:39 +0300 Subject: [PATCH 02/18] fix typo --- main/extra_func.py | 8 ++++---- main/views.py | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/main/extra_func.py b/main/extra_func.py index a5ca8d2..6d74db6 100644 --- a/main/extra_func.py +++ b/main/extra_func.py @@ -7,7 +7,7 @@ def set_and_get_username(UP: UserProfile): # TODO: Переделать с по Функция устанавливает поле :class:`user.username` текущим именем в Zendesk :param UP: Объект профиля пользователя - :type UP: :class:`UserProfile` + :type UP: :class:`main.models.UserProfile` :return: Имя пользователя """ return UP.user.username @@ -18,7 +18,7 @@ def set_and_get_email(UP: UserProfile): # TODO: Переделать с пол Функция устанавливает поле :class:`user.email` текущей почтой в Zendesk :param UP: Объект профиля пользователя - :type UP: :class:`UserProfile` + :type UP: :class:`main.models.UserProfile` :return: Почта пользователя """ return UP.user.email @@ -29,7 +29,7 @@ def set_and_get_role(UP: UserProfile): # TODO: Переделать с полу Функция устанавливает поле :class:`role` текущей ролью в Zendesk :param UP: Объект профиля пользователя - :type UP: :class:`UserProfile` + :type UP: :class:`main.models.UserProfile` :return: Роль пользователя """ return UP.role @@ -40,7 +40,7 @@ def load_and_get_image(UP: UserProfile): # TODO: Переделать с пол Функция загружает и устанавливает изображение в поле :class:`image` :param UP: Объект профиля пользователя - :type UP: :class:`UserProfile` + :type UP: :class:`main.models.UserProfile` :return: Название изображения """ return UP.image.name diff --git a/main/views.py b/main/views.py index 19fe76c..39054cc 100644 --- a/main/views.py +++ b/main/views.py @@ -11,7 +11,7 @@ def profile_page(request): Отображение страницы профиля :param request: объект с деталями запроса - :type request: :class:`django.http.HttpResponse + :type request: :class:`django.http.HttpResponse` :return: объект ответа сервера с HTML-кодом внутри """ if request.user.is_authenticated: From 0583e350dbac6cfd973d7526dd3d2d4cd6b1d574 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=A1=D0=BE=D0=BA=D1=83=D1=80=D0=BE=D0=B2=20=D0=98=D0=B4?= =?UTF-8?q?=D0=B0=D1=80?= Date: Sat, 6 Feb 2021 12:27:45 +0000 Subject: [PATCH 03/18] Add request access button --- main/templates/pages/profile.html | 3 +++ 1 file changed, 3 insertions(+) diff --git a/main/templates/pages/profile.html b/main/templates/pages/profile.html index c6c1780..4066d5a 100644 --- a/main/templates/pages/profile.html +++ b/main/templates/pages/profile.html @@ -29,6 +29,9 @@

Имя пользователя {{name}}

Электронная почта {{email}}

Текущая роль {{role}}

+
+ +
From b5dfc4935c2dd17013fd5c2a4d817f6c3dc46af9 Mon Sep 17 00:00:00 2001 From: Dmitriy Andreev Date: Sun, 7 Feb 2021 15:10:45 +0300 Subject: [PATCH 04/18] Added base.html layout --- main/layout/base/base.png | Bin 0 -> 56050 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 main/layout/base/base.png diff --git a/main/layout/base/base.png b/main/layout/base/base.png new file mode 100644 index 0000000000000000000000000000000000000000..0841addd2c578ddc4141cb9f5f77347368d28279 GIT binary patch literal 56050 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 literal 0 HcmV?d00001 From d686a1566e4a8c60ea27abb243d37c0bdf4f89ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=A1=D0=BE=D0=BA=D1=83=D1=80=D0=BE=D0=B2=20=D0=98=D0=B4?= =?UTF-8?q?=D0=B0=D1=80?= Date: Sun, 7 Feb 2021 14:13:50 +0000 Subject: [PATCH 05/18] Small fix profile.html --- main/templates/base/base.html | 4 +--- main/templates/pages/profile.html | 2 ++ 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/main/templates/base/base.html b/main/templates/base/base.html index b53080c..e6d3628 100644 --- a/main/templates/base/base.html +++ b/main/templates/base/base.html @@ -9,9 +9,7 @@ integrity="sha384-giJF6kkoqNQ00vy+HMDP7azOuL0xtbfIcaT9wjKHr8RbDVddVHyTfAAsrekwKmP1" crossorigin="anonymous" /> - + {% block extra_css %}{% endblock %} diff --git a/main/templates/pages/profile.html b/main/templates/pages/profile.html index 4066d5a..b6ee09c 100644 --- a/main/templates/pages/profile.html +++ b/main/templates/pages/profile.html @@ -10,11 +10,13 @@ {% endblock %} {% block extra_css%} + } {% endblock %} {% block content %} From f6193a837aff5965cc331aa59283a4b6bad0ccf0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9A=D1=83=D0=BB=D0=B0=D0=BA=D0=BE=D0=B2=20=D0=AE=D1=80?= =?UTF-8?q?=D0=B8=D0=B9?= Date: Sun, 7 Feb 2021 20:17:27 +0300 Subject: [PATCH 06/18] Added authorization page --- access_controller/settings.py | 3 ++ access_controller/urls.py | 3 +- layouts/authorization/authorization.jpg | Bin 0 -> 28006 bytes main/templates/registration/login.html | 37 ++++++++++++++++++++++++ 4 files changed, 42 insertions(+), 1 deletion(-) create mode 100644 layouts/authorization/authorization.jpg create mode 100644 main/templates/registration/login.html diff --git a/access_controller/settings.py b/access_controller/settings.py index dc44189..bc9a972 100644 --- a/access_controller/settings.py +++ b/access_controller/settings.py @@ -126,3 +126,6 @@ STATICFILES_DIRS = [ ] MEDIA_ROOT = BASE_DIR / 'media' + +LOGIN_REDIRECT_URL = '/' +LOGOUT_REDIRECT_URL = '/' diff --git a/access_controller/urls.py b/access_controller/urls.py index e0ecf63..40a67d5 100644 --- a/access_controller/urls.py +++ b/access_controller/urls.py @@ -14,8 +14,9 @@ Including another URLconf 2. Add a URL to urlpatterns: path('blog/', include('blog.urls')) """ from django.contrib import admin -from django.urls import path +from django.urls import path, include urlpatterns = [ path('admin/', admin.site.urls), + path('accounts/', include('django.contrib.auth.urls')), ] diff --git a/layouts/authorization/authorization.jpg b/layouts/authorization/authorization.jpg new file mode 100644 index 0000000000000000000000000000000000000000..8860ad9c8747b76266173fdf421dfd111d55a7de GIT binary patch literal 28006 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 +

+
+ +
+ {% csrf_token %} + {% for field in form %} + + + {% endfor %} + {% if form.non_field_errors %} +
    + {% for error in form.non_field_errors %} +
  • {{ error }}
  • + {% endfor %} +
+ {% endif %} +
+ + Забыли пароль? +
+
+
+
+ +{% endblock %} From d1dcb9b1bf00083bc628c75b73d0650581670658 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9A=D1=83=D0=BB=D0=B0=D0=BA=D0=BE=D0=B2=20=D0=AE=D1=80?= =?UTF-8?q?=D0=B8=D0=B9?= Date: Sun, 7 Feb 2021 20:28:15 +0300 Subject: [PATCH 07/18] Added additional LoginView in the urls.py to define extra_context later --- access_controller/urls.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/access_controller/urls.py b/access_controller/urls.py index 40a67d5..ce12048 100644 --- a/access_controller/urls.py +++ b/access_controller/urls.py @@ -14,9 +14,12 @@ Including another URLconf 2. Add a URL to urlpatterns: path('blog/', include('blog.urls')) """ from django.contrib import admin +from django.contrib.auth.views import LoginView from django.urls import path, include urlpatterns = [ path('admin/', admin.site.urls), - path('accounts/', include('django.contrib.auth.urls')), + path('accounts/login/', LoginView.as_view(extra_context={})), # TODO add extra context + path('accounts/', include('django.contrib.auth.urls')) + ] From b8e3d11c6f9d397fd6448a87c97a110bba05ec60 Mon Sep 17 00:00:00 2001 From: Sokurov Idar Date: Mon, 8 Feb 2021 19:10:44 +0300 Subject: [PATCH 08/18] Add first version registration --- access_controller/settings.py | 1 + access_controller/urls.py | 5 ++- .../django_registration_complete.html | 10 +++++ .../registration_form.html | 20 ++++++++++ main/views.py | 39 ++++++++++++++++++- 5 files changed, 72 insertions(+), 3 deletions(-) create mode 100644 main/templates/django_registration/django_registration_complete.html create mode 100644 main/templates/django_registration/registration_form.html diff --git a/access_controller/settings.py b/access_controller/settings.py index dc44189..8f61695 100644 --- a/access_controller/settings.py +++ b/access_controller/settings.py @@ -37,6 +37,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 e0ecf63..eb189ef 100644 --- a/access_controller/urls.py +++ b/access_controller/urls.py @@ -16,6 +16,9 @@ Including another URLconf from django.contrib import admin from django.urls import path +from main.views import Reg + urlpatterns = [ - path('admin/', admin.site.urls), + path('admin/', admin.site.urls, name='admin'), + path('register/', Reg.as_view(), name='registration'), ] diff --git a/main/templates/django_registration/django_registration_complete.html b/main/templates/django_registration/django_registration_complete.html new file mode 100644 index 0000000..61a69c0 --- /dev/null +++ b/main/templates/django_registration/django_registration_complete.html @@ -0,0 +1,10 @@ + + + + + Title + + +NIce + + diff --git a/main/templates/django_registration/registration_form.html b/main/templates/django_registration/registration_form.html new file mode 100644 index 0000000..6b84e1d --- /dev/null +++ b/main/templates/django_registration/registration_form.html @@ -0,0 +1,20 @@ + + + + + Title + + +

Регистрация

+
+ {% csrf_token %} + {% for field in form %} + {{ field.label_tag }} + {{ field }} +
+ {% if field.errors %}
{{ field.errors }}
{% endif %} +{% endfor %} + + + + diff --git a/main/views.py b/main/views.py index 91ea44a..a6208c4 100644 --- a/main/views.py +++ b/main/views.py @@ -1,3 +1,38 @@ -from django.shortcuts import render - # Create your views here. +from abc import ABC + +from django.contrib.auth.models import User +from django.urls import reverse_lazy +from django_registration.forms import RegistrationFormUniqueEmail +from django_registration.views import RegistrationView +from zenpy import Zenpy + +from main.models import UserProfile + + +class Reg(RegistrationView): + form_class = RegistrationFormUniqueEmail + template_name = 'django_registration/registration_form.html' + + def register(self, form): + creds = { + 'email': 'DEFINEME', + 'subdomain': 'ngenix1612197338', + 'token': 'DEFINEME', + } + client = Zenpy(**creds) + zenpy_user = client.search(form.data['email'], type='user') + if zenpy_user: + user = User.objects.create_user( + username=form.data['username'], + email=form.data['email'], + password=form.data['email'], + ) + profile=UserProfile.objects.create( + image='None.png', + user=user, + role='None' + ) + user.save() + else: + raise AttributeError('No such email') From 729c0bec7ec6f301fea492b16e3035e3ba57c1ff Mon Sep 17 00:00:00 2001 From: Sokurov Idar Date: Mon, 8 Feb 2021 20:12:24 +0300 Subject: [PATCH 09/18] Email on zendesk exist check --- access_controller/urls.py | 8 ++-- main/extra_func.py | 4 +- main/migrations/0002_userprofile_name.py | 18 ++++++++ main/models.py | 1 + .../django_registration_complete.html | 10 ----- .../registration_closed.html | 15 +++++++ .../registration_complete.html | 14 +++++++ .../registration_form.html | 42 ++++++++++--------- main/views.py | 29 +++++++------ requirements.txt | 2 + 10 files changed, 95 insertions(+), 48 deletions(-) create mode 100644 main/migrations/0002_userprofile_name.py delete mode 100644 main/templates/django_registration/django_registration_complete.html create mode 100644 main/templates/django_registration/registration_closed.html create mode 100644 main/templates/django_registration/registration_complete.html diff --git a/access_controller/urls.py b/access_controller/urls.py index b9f7386..9262d42 100644 --- a/access_controller/urls.py +++ b/access_controller/urls.py @@ -15,15 +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, name='admin'), - path('register/', Reg.as_view(), name='registration'), - path('admin/', admin.site.urls), - path('profile/', profile_page, name="Profile"), + 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..487fb13 100644 --- a/main/extra_func.py +++ b/main/extra_func.py @@ -2,9 +2,9 @@ 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` 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/django_registration_complete.html b/main/templates/django_registration/django_registration_complete.html deleted file mode 100644 index 61a69c0..0000000 --- a/main/templates/django_registration/django_registration_complete.html +++ /dev/null @@ -1,10 +0,0 @@ - - - - - Title - - -NIce - - diff --git a/main/templates/django_registration/registration_closed.html b/main/templates/django_registration/registration_closed.html new file mode 100644 index 0000000..9aa808d --- /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..8da81c0 --- /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 index 6b84e1d..c4bb388 100644 --- a/main/templates/django_registration/registration_form.html +++ b/main/templates/django_registration/registration_form.html @@ -1,20 +1,24 @@ - - - - - Title - - -

Регистрация

- - {% csrf_token %} - {% for field in form %} - {{ field.label_tag }} - {{ field }} -
- {% if field.errors %}
{{ field.errors }}
{% endif %} -{% endfor %} +{% 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 c8271ee..2de5f8b 100644 --- a/main/views.py +++ b/main/views.py @@ -1,26 +1,25 @@ from django.shortcuts import render, redirect +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 from main.models import UserProfile from django.contrib.auth.models import User -from django.urls import reverse_lazy from django_registration.forms import RegistrationFormUniqueEmail from django_registration.views import RegistrationView from zenpy import Zenpy -from main.models import UserProfile - -class Reg(RegistrationView): +class CustomRegistrationView(RegistrationView): form_class = RegistrationFormUniqueEmail template_name = 'django_registration/registration_form.html' + success_url = reverse_lazy('django_registration_complete') def register(self, form): creds = { - 'email': 'DEFINEME', + 'email': 'idar.sokurov.05@mail.ru', 'subdomain': 'ngenix1612197338', - 'token': 'DEFINEME', + 'token': 'xRL9Qqz7svFE3X9cHMVC2zOtJUdllzr441C3Z363', } client = Zenpy(**creds) zenpy_user = client.search(form.data['email'], type='user') @@ -28,16 +27,20 @@ class Reg(RegistrationView): user = User.objects.create_user( username=form.data['username'], email=form.data['email'], - password=form.data['email'], + password=form.data['password1'] ) - profile = UserProfile.objects.create( + profile = UserProfile( image='None.png', user=user, - role='None' + role=0, ) - user.save() + set_and_get_name(profile) + set_and_get_email(profile) + set_and_get_role(profile) + load_and_get_image(profile) + profile.save() else: - raise AttributeError('No such email') + self.success_url = reverse_lazy('django_registration_disallowed') def profile_page(request): @@ -53,7 +56,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 + From 0bc34f810090d10097879124af7273216817a18c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=A1=D0=BE=D0=BA=D1=83=D1=80=D0=BE=D0=B2=20=D0=98=D0=B4?= =?UTF-8?q?=D0=B0=D1=80?= Date: Mon, 8 Feb 2021 17:17:03 +0000 Subject: [PATCH 10/18] Update main/views.py, README.md files --- README.md | 1 + main/views.py | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 4230f3c..f27d6b3 100644 --- a/README.md +++ b/README.md @@ -46,6 +46,7 @@ pip install -r requirements.txt ./manage.py migrate ./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 +Создать токен и указать вместе с почтой в запросах к Zendesk ``` ## Read more diff --git a/main/views.py b/main/views.py index 2de5f8b..e377db5 100644 --- a/main/views.py +++ b/main/views.py @@ -17,9 +17,9 @@ class CustomRegistrationView(RegistrationView): def register(self, form): creds = { - 'email': 'idar.sokurov.05@mail.ru', + 'email': 'DEFINE ME', 'subdomain': 'ngenix1612197338', - 'token': 'xRL9Qqz7svFE3X9cHMVC2zOtJUdllzr441C3Z363', + 'token': 'DEFINE ME', } client = Zenpy(**creds) zenpy_user = client.search(form.data['email'], type='user') From 4326d12b5c03c6c91076dd8214b723853f043ec4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9A=D1=83=D0=BB=D0=B0=D0=BA=D0=BE=D0=B2=20=D0=AE=D1=80?= =?UTF-8?q?=D0=B8=D0=B9?= Date: Tue, 9 Feb 2021 23:42:23 +0300 Subject: [PATCH 11/18] Login template now extends base/base.html --- main/templates/base/base.html | 2 +- main/templates/base/menu.html | 6 +++--- main/templates/registration/login.html | 3 +++ 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/main/templates/base/base.html b/main/templates/base/base.html index e41acf5..737fa73 100644 --- a/main/templates/base/base.html +++ b/main/templates/base/base.html @@ -31,7 +31,7 @@
-

+

{% block heading %} {% endblock %}

diff --git a/main/templates/base/menu.html b/main/templates/base/menu.html index ca31bd0..a7c0c3f 100644 --- a/main/templates/base/menu.html +++ b/main/templates/base/menu.html @@ -10,15 +10,15 @@ {% if request.user.is_authenticated %} {% else %} {% endif %} diff --git a/main/templates/registration/login.html b/main/templates/registration/login.html index fc930f2..0917b0c 100644 --- a/main/templates/registration/login.html +++ b/main/templates/registration/login.html @@ -2,6 +2,9 @@ {% block title %} Авторизация {% endblock %} +{% block heading %} + Авторизация +{% endblock %} {% block content %}
From 938b9894fe12e98ea6fd10aba0cea4f60533c059 Mon Sep 17 00:00:00 2001 From: Sokurov Idar Date: Wed, 10 Feb 2021 19:05:46 +0300 Subject: [PATCH 12/18] Add Zendesk password check Add Bootstrap to forms Add custom form --- main/extra_func.py | 55 +++++++++++++++++++ main/forms.py | 34 ++++++++++++ .../registration_closed.html | 2 +- .../registration_complete.html | 2 +- main/views.py | 35 +++++++----- 5 files changed, 112 insertions(+), 16 deletions(-) create mode 100644 main/forms.py diff --git a/main/extra_func.py b/main/extra_func.py index 487fb13..8f850b8 100644 --- a/main/extra_func.py +++ b/main/extra_func.py @@ -1,3 +1,8 @@ +import os + +from zenpy import Zenpy +from zenpy.lib.exception import APIException + from main.models import UserProfile @@ -9,6 +14,7 @@ def set_and_get_name(UP: UserProfile): # TODO: Переделать с полу :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/templates/django_registration/registration_closed.html b/main/templates/django_registration/registration_closed.html index 9aa808d..4fffce6 100644 --- a/main/templates/django_registration/registration_closed.html +++ b/main/templates/django_registration/registration_closed.html @@ -11,5 +11,5 @@ {% block content %}
-

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

+

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

{% endblock %} diff --git a/main/templates/django_registration/registration_complete.html b/main/templates/django_registration/registration_complete.html index 8da81c0..bb064bb 100644 --- a/main/templates/django_registration/registration_complete.html +++ b/main/templates/django_registration/registration_complete.html @@ -10,5 +10,5 @@ {% block content %}
-

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

+

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

{% endblock %} diff --git a/main/views.py b/main/views.py index 2de5f8b..c02dd4d 100644 --- a/main/views.py +++ b/main/views.py @@ -1,29 +1,26 @@ -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_name, 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 django_registration.forms import RegistrationFormUniqueEmail +from main.forms import CustomRegistrationForm from django_registration.views import RegistrationView -from zenpy import Zenpy class CustomRegistrationView(RegistrationView): - form_class = RegistrationFormUniqueEmail + """ + Отображение и логика работы страницы регистрации пользователя + """ + form_class = CustomRegistrationForm template_name = 'django_registration/registration_form.html' success_url = reverse_lazy('django_registration_complete') + is_allowed = True def register(self, form): - creds = { - 'email': 'idar.sokurov.05@mail.ru', - 'subdomain': 'ngenix1612197338', - 'token': 'xRL9Qqz7svFE3X9cHMVC2zOtJUdllzr441C3Z363', - } - client = Zenpy(**creds) - zenpy_user = client.search(form.data['email'], type='user') - if zenpy_user: + 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'], @@ -40,7 +37,17 @@ class CustomRegistrationView(RegistrationView): load_and_get_image(profile) profile.save() else: - self.success_url = reverse_lazy('django_registration_disallowed') + 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') def profile_page(request): From 8de78e06c44bdba96e052701bb95baa363238acd Mon Sep 17 00:00:00 2001 From: Sokurov Idar Date: Wed, 10 Feb 2021 19:16:27 +0300 Subject: [PATCH 13/18] Merge branch 'feature/registration' --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index f27d6b3..db34259 100644 --- a/README.md +++ b/README.md @@ -46,8 +46,10 @@ pip install -r requirements.txt ./manage.py migrate ./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 -Создать токен и указать вместе с почтой в запросах к Zendesk ``` +Создать токен + +Указать почту и токен в окружении ## Read more - Zenpy: [http://docs.facetoe.com.au](http://docs.facetoe.com.au) From 9cdcdb7a0c544fea299a6927d84f848057afe9e5 Mon Sep 17 00:00:00 2001 From: Artyom Kravchenko Date: Wed, 10 Feb 2021 23:29:28 +0300 Subject: [PATCH 14/18] fixed registrarion/requirements --- main/views.py | 5 ++++- requirements.txt | 2 ++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/main/views.py b/main/views.py index dfd4c48..93ee8d6 100644 --- a/main/views.py +++ b/main/views.py @@ -8,6 +8,9 @@ from main.models import UserProfile from django.contrib.auth.models import User from main.forms import CustomRegistrationForm from django_registration.views import RegistrationView + +from django.contrib.auth.decorators import login_required + from zenpy import Zenpy @@ -50,7 +53,7 @@ class CustomRegistrationView(RegistrationView): else: return reverse_lazy('django_registration_disallowed') - +#@login_required() def profile_page(request): """ Отображение страницы профиля diff --git a/requirements.txt b/requirements.txt index f51fa7a..e40b267 100644 --- a/requirements.txt +++ b/requirements.txt @@ -2,6 +2,8 @@ Django==3.1.6 Pillow==8.1.0 zenpy~=2.0.24 +django-registration==3.1.1 + # Documentation Sphinx==3.4.3 From c5bdb7cb6ff24321f9c4a3d83a03456fa96f6cfd Mon Sep 17 00:00:00 2001 From: Artyom Kravchenko Date: Thu, 11 Feb 2021 00:02:22 +0300 Subject: [PATCH 15/18] add login_required to profile view --- main/views.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/main/views.py b/main/views.py index 93ee8d6..44faa65 100644 --- a/main/views.py +++ b/main/views.py @@ -53,19 +53,20 @@ class CustomRegistrationView(RegistrationView): else: return reverse_lazy('django_registration_disallowed') -#@login_required() +@login_required() def profile_page(request): """ Отображение страницы профиля + :param request: объект с деталями запроса :type request: :class:`django.http.HttpResponse` :return: объект ответа сервера с HTML-кодом внутри """ if request.user.is_authenticated: UP = UserProfile.objects.get(user=request.user) - else: # TODO: Убрать после появления регистрации и авторизации, добавить login_required() - UP = UserProfile.objects.get(user=1) + #else: # TODO: Убрать после появления регистрации и авторизации, добавить login_required() + #UP = UserProfile.objects.get(user=1) context = { 'name': set_and_get_name(UP), 'email': set_and_get_email(UP), From 8024d38e09141484e3a25580c480ffd2c51ece70 Mon Sep 17 00:00:00 2001 From: Andrew Smirnov Date: Thu, 11 Feb 2021 19:44:35 +0300 Subject: [PATCH 16/18] Fix non-existing profile avatar --- main/templates/pages/profile.html | 68 ++++++++++++++++-------------- static/no_avatar.png | Bin 0 -> 16427 bytes 2 files changed, 37 insertions(+), 31 deletions(-) create mode 100644 static/no_avatar.png diff --git a/main/templates/pages/profile.html b/main/templates/pages/profile.html index b6ee09c..0b855b4 100644 --- a/main/templates/pages/profile.html +++ b/main/templates/pages/profile.html @@ -1,40 +1,46 @@ {% extends 'base/base.html' %} + {% load static %} -{% block title %} - {{ pagename }} + +{% block title %}{{ pagename }}{% endblock %} + + +{% block heading %}Профиль{% endblock %} + + +{% block extra_css %} + {% endblock %} -{% block heading %} - Профиль -{% endblock %} - -{% block extra_css%} - - } -{% endblock %} {% block content %} -
-
-
-
- Нет изображения
-
-
-
-

Имя пользователя {{name}}

-

Электронная почта {{email}}

-

Текущая роль {{role}}

-
- -
-
+
+
+
+
+ {% if image_name %} + Аватар + {% else %} + Нет изображения + {% endif %}
+
+
+

Имя пользователя {{name}}

+

Электронная почта {{email}}

+

Текущая роль {{role}}

+
+ +
+
+
+
{% endblock %} diff --git a/static/no_avatar.png b/static/no_avatar.png new file mode 100644 index 0000000000000000000000000000000000000000..25938748b51b2785b6ab796659dc78b72d655152 GIT binary patch literal 16427 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 literal 0 HcmV?d00001 From c3f9e6626b842f49b4352f95ea17a13930bb2f6f Mon Sep 17 00:00:00 2001 From: Andrew Smirnov Date: Thu, 11 Feb 2021 20:04:08 +0300 Subject: [PATCH 17/18] Add extra_funcs to documentation --- docs/source/code.rst | 9 +++++++++ docs/source/index.rst | 3 +++ docs/source/todo.rst | 5 +++++ main/extra_func.py | 11 +++++++---- 4 files changed, 24 insertions(+), 4 deletions(-) create mode 100644 docs/source/code.rst create mode 100644 docs/source/todo.rst diff --git a/docs/source/code.rst b/docs/source/code.rst new file mode 100644 index 0000000..27ac9c9 --- /dev/null +++ b/docs/source/code.rst @@ -0,0 +1,9 @@ +***** +TODOs +***** + +Extra Functions +--------------- + +.. automodule:: main.extra_func + :members: diff --git a/docs/source/index.rst b/docs/source/index.rst index a95aa50..778a091 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -6,10 +6,13 @@ Welcome to ZenDesk Access Controller's documentation! ===================================================== + .. toctree:: :maxdepth: 2 :caption: Contents: + code.rst + todo.rst Indices and tables diff --git a/docs/source/todo.rst b/docs/source/todo.rst new file mode 100644 index 0000000..d6ad446 --- /dev/null +++ b/docs/source/todo.rst @@ -0,0 +1,5 @@ +***** +TODOs +***** + +.. todolist:: diff --git a/main/extra_func.py b/main/extra_func.py index 8f850b8..50eecc6 100644 --- a/main/extra_func.py +++ b/main/extra_func.py @@ -7,10 +7,13 @@ from main.models import UserProfile # Дополнительные функции -def set_and_get_name(UP: UserProfile): # TODO: Переделать с получением данных через API +def set_and_get_name(UP: UserProfile): """ Функция устанавливает поле :class:`username` текущим именем в Zendesk + .. TODO:: + Переделать с получением данных через API + :param UP: Объект профиля пользователя :type UP: :class:`main.models.UserProfile` :return: Имя пользователя @@ -60,9 +63,9 @@ def check_user_exist(email: str) -> bool: Функция проверяет, существует ли пользователь :param email: Электронная почта пользователя - :type email: :class:`str + :type email: :class:`str` :return: True, если существует, иначе False - :rtype: :class:`bool' + :rtype: :class:`bool` """ admin_creds = { 'email': os.environ.get('Admin_email'), @@ -85,7 +88,7 @@ def check_user_auth(email: str, password: str) -> bool: :param password: Пароль пользователя :type password: :class:`str` :return: True, если входные данные верны, иначе False - :raise APIException: исключение, вызываемое если пользователь не аутентифицирован + :raise :class:`APIException`: исключение, вызываемое если пользователь не аутентифицирован :rtype: :class:`bool` """ try: From ac99a23a3b12b20225959768c91cda3800bad84a Mon Sep 17 00:00:00 2001 From: Andrew Smirnov Date: Thu, 11 Feb 2021 20:15:46 +0300 Subject: [PATCH 18/18] Small code style improvements --- access_controller/urls.py | 7 ++----- main/extra_func.py | 16 ++++++++-------- main/views.py | 13 ++++++------- 3 files changed, 16 insertions(+), 20 deletions(-) diff --git a/access_controller/urls.py b/access_controller/urls.py index 0063265..350e189 100644 --- a/access_controller/urls.py +++ b/access_controller/urls.py @@ -26,13 +26,10 @@ urlpatterns = [ path('admin/', admin.site.urls, name='admin'), path('', main_page), path('register/', CustomRegistrationView.as_view(), name='registration'), - #path('', include('django_registration.backends.one_step.urls')), + # path('', include('django_registration.backends.one_step.urls')), path('profile/', profile_page, name='profile'), path('accounts/login/', LoginView.as_view(extra_context={})), # TODO add extra context path('accounts/', include('django.contrib.auth.urls')) - ] - - - +] urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT) diff --git a/main/extra_func.py b/main/extra_func.py index 50eecc6..305e897 100644 --- a/main/extra_func.py +++ b/main/extra_func.py @@ -7,7 +7,7 @@ from main.models import UserProfile # Дополнительные функции -def set_and_get_name(UP: UserProfile): +def set_and_get_name(user_profile: UserProfile): """ Функция устанавливает поле :class:`username` текущим именем в Zendesk @@ -19,10 +19,10 @@ def set_and_get_name(UP: UserProfile): :return: Имя пользователя :rtype: :class:`str` """ - return UP.user.username + return user_profile.user.username -def set_and_get_email(UP: UserProfile): # TODO: Переделать с получением данных через API +def set_and_get_email(user_profile: UserProfile): # TODO: Переделать с получением данных через API """ Функция устанавливает поле :class:`user.email` текущей почтой в Zendesk @@ -31,10 +31,10 @@ def set_and_get_email(UP: UserProfile): # TODO: Переделать с пол :return: Почта пользователя :rtype: :class:`str` """ - return UP.user.email + return user_profile.user.email -def set_and_get_role(UP: UserProfile): # TODO: Переделать с получением данных через API +def set_and_get_role(user_profile: UserProfile): # TODO: Переделать с получением данных через API """ Функция устанавливает поле :class:`role` текущей ролью в Zendesk @@ -43,10 +43,10 @@ def set_and_get_role(UP: UserProfile): # TODO: Переделать с полу :return: Роль пользователя :rtype: :class:`str` """ - return UP.role + return user_profile.role -def load_and_get_image(UP: UserProfile): # TODO: Переделать с получением изображения через API +def load_and_get_image(user_profile: UserProfile): # TODO: Переделать с получением изображения через API """ Функция загружает и устанавливает изображение в поле :class:`image` @@ -55,7 +55,7 @@ def load_and_get_image(UP: UserProfile): # TODO: Переделать с пол :return: Название изображения :rtype: :class:`str` """ - return UP.image.name + return user_profile.image.name def check_user_exist(email: str) -> bool: diff --git a/main/views.py b/main/views.py index bd260b2..8dbfe9d 100644 --- a/main/views.py +++ b/main/views.py @@ -1,7 +1,6 @@ from django.shortcuts import render from django.urls import reverse_lazy - 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 @@ -44,9 +43,9 @@ class CustomRegistrationView(RegistrationView): else: self.is_allowed = False - def get_success_url(self, request): + def get_success_url(self, user=None): """ - Вовзращет url-адресс страницы, куда нужно перейти после успешной/неуспешной регистрации + Возвращает url-адрес страницы, куда нужно перейти после успешной/неуспешной регистрации Используется самой django-registration """ if self.is_allowed: @@ -54,6 +53,7 @@ class CustomRegistrationView(RegistrationView): else: return reverse_lazy('django_registration_disallowed') + @login_required() def profile_page(request): """ @@ -65,10 +65,10 @@ def profile_page(request): :return: объект ответа сервера с HTML-кодом внутри """ if request.user.is_authenticated: - #UP = UserProfile.objects.get(user=request.user) + # UP = UserProfile.objects.get(user=request.user) UP = UserProfile.objects.get(user=request.user) - #else: # TODO: Убрать после появления регистрации и авторизации, добавить login_required() - #UP = UserProfile.objects.get(user=1) + # else: # TODO: Убрать после появления регистрации и авторизации, добавить login_required() + # UP = UserProfile.objects.get(user=1) context = { 'name': set_and_get_name(UP), 'email': set_and_get_email(UP), @@ -81,4 +81,3 @@ def profile_page(request): def main_page(request): return render(request, 'pages/index.html') -