diff --git a/access_controller/auth.py b/access_controller/auth.py new file mode 100644 index 0000000..be707e1 --- /dev/null +++ b/access_controller/auth.py @@ -0,0 +1,19 @@ +from django.contrib.auth.backends import ModelBackend +from django.contrib.auth.models import User + + +class EmailAuthBackend(ModelBackend): + def authenticate(self, request, username=None, password=None, **kwargs): + try: + user = User.objects.get(email=username) + if user.check_password(password): + return user + return None + except User.DoesNotExist: + return None + + def get_user(self, user_id): + try: + return User.objects.get(pk=user_id) + except User.DoesNotExist: + return None diff --git a/access_controller/settings.py b/access_controller/settings.py index febc172..96703b6 100644 --- a/access_controller/settings.py +++ b/access_controller/settings.py @@ -135,6 +135,12 @@ ACCOUNT_ACTIVATION_DAYS = 7 LOGIN_REDIRECT_URL = '/' LOGOUT_REDIRECT_URL = '/' + +# Название_приложения.Название_файла.Название_класса_обработчика +AUTHENTICATION_BACKENDS = [ + 'access_controller.auth.EmailAuthBackend', +] + # Logging system # https://docs.djangoproject.com/en/3.1/topics/logging/ LOGGING = { diff --git a/access_controller/urls.py b/access_controller/urls.py index 5420838..45d815b 100644 --- a/access_controller/urls.py +++ b/access_controller/urls.py @@ -14,18 +14,27 @@ Including another URLconf 2. Add a URL to urlpatterns: path('blog/', include('blog.urls')) """ from django.contrib import admin +from django.contrib.auth.forms import AuthenticationForm from django.contrib.auth.views import LoginView from django.contrib.auth import views as auth_views from django.urls import path, include -from main.views import main_page, profile_page, CustomRegistrationView, AdminPageView +from access_controller import settings +from access_controller.settings import DEBUG +from main.views import main_page, profile_page, CustomRegistrationView, work_page, work_hand_over, work_become_engineer, AdminPageView + +from main.views import main_page, profile_page, CustomRegistrationView, CustomLoginView urlpatterns = [ path('admin/', admin.site.urls, name='admin'), path('', main_page, name='index'), path('accounts/profile/', profile_page, name='profile'), path('accounts/register/', CustomRegistrationView.as_view(), name='registration'), - path('accounts/login/', LoginView.as_view(extra_context={}), name='login'), # TODO add extra context + path('accounts/login/', CustomLoginView.as_view(extra_context={}), name='login',), # TODO add extra context path('accounts/', include('django.contrib.auth.urls')), + path('accounts/', include('django_registration.backends.one_step.urls')), + path('work/', work_page, name="work"), + path('work/hand_over/', work_hand_over, name="work_hand_over"), + path('work/become_engineer/', work_become_engineer, name="work_become_engineer"), path('accounts/', include('django_registration.backends.activation.urls')), path('accounts/login/', include('django.contrib.auth.urls')), path('control/', AdminPageView.as_view(), name='control') diff --git a/main/extra_func.py b/main/extra_func.py index b07f242..6227bf1 100644 --- a/main/extra_func.py +++ b/main/extra_func.py @@ -20,7 +20,6 @@ class ZendeskAdmin: :type token: :class:`str` :param password: Пароль администратора, указанный в env :type password: :class:`str` - """ credentials: dict = { @@ -29,6 +28,12 @@ class ZendeskAdmin: email: str = os.getenv('ACCESS_CONTROLLER_API_EMAIL') token: str = os.getenv('ACCESS_CONTROLLER_API_TOKEN') password: str = os.getenv('ACCESS_CONTROLLER_API_PASSWORD') + _instance=None + + def __new__(cls, *args, **kwargs): + if cls._instance is None: + cls._instance = super().__new__(cls) + return cls._instance def __init__(self): self.create_admin() @@ -62,7 +67,7 @@ class ZendeskAdmin: def get_user_image(self, email: str) -> str: """ - Функция **get_user_image** возвращает аватар пользователя по его email + Функция **get_user_image** возвращает url-ссылку на аватар пользователя по его email """ user = self.admin.users.search(email).values[0] return user.photo['content_url'] if user.photo else None @@ -78,7 +83,7 @@ class ZendeskAdmin: Функция **get_user_org** возвращает организацию, к которой относится пользователь по его email """ user = self.admin.users.search(email).values[0] - return user.organization + return user.organization.name def create_admin(self) -> Zenpy: """ diff --git a/main/forms.py b/main/forms.py index 63a3556..a9624dd 100644 --- a/main/forms.py +++ b/main/forms.py @@ -1,4 +1,5 @@ from django import forms +from django.contrib.auth.forms import AuthenticationForm from django_registration.forms import RegistrationFormUniqueEmail from main.models import UserProfile @@ -46,3 +47,21 @@ class AdminPageUsers(forms.Form): ), label='' ) + + +class CustomAuthenticationForm(AuthenticationForm): + """ + Форма для авторизации :class:`django.contrib.auth.forms.AuthenticationForm` + с изменением поля username на email + """ + username = forms.CharField( + label="Электронная почта", + widget=forms.EmailInput(), + ) + error_messages = { + 'invalid_login': + "Пожалуйста, введите правильные электронную почту и пароль. Оба поля " + "могут быть чувствительны к регистру." + , + 'inactive': "Аккаунт не активен.", + } diff --git a/main/templates/pages/profile.html b/main/templates/pages/profile.html index bfd8cd7..6c6ecd2 100644 --- a/main/templates/pages/profile.html +++ b/main/templates/pages/profile.html @@ -45,7 +45,7 @@
- + Запросить права доступа
{% endblock %} diff --git a/main/templates/pages/work.html b/main/templates/pages/work.html index bd760cb..2fcb4cf 100644 --- a/main/templates/pages/work.html +++ b/main/templates/pages/work.html @@ -4,7 +4,7 @@ {% block title %}{{ pagename }}{% endblock %} -{% block heading %}Управление{% endblock %} +{% block heading %}Управление правами{% endblock %} {% block extra_css %} @@ -23,24 +23,15 @@ - - - + - - - - - - - - - - - - - + {% for engineer in engineers %} + + + + + {% endfor %}
IDemailExpiration DateName(link to profile)Name
1big_boss123@example.ru19:30 18.02.21Иван Иванов
2gachi_cool456@example.ru21:00 18.02.21Пётр Петров
{{ engineer.id }}{{ engineer.name }}
@@ -52,23 +43,24 @@
инженеров:
- 13 + {{ engineers|length }}
легких агентов:
- 22 + {{ agents|length }}
- +
- - + Получить права инженера + Сдать права инженера
-{% endblock %} \ No newline at end of file +{% endblock %} + diff --git a/main/views.py b/main/views.py index c7c1849..b96aad1 100644 --- a/main/views.py +++ b/main/views.py @@ -1,27 +1,26 @@ +import logging +import os + from django.contrib.auth.decorators import login_required from django.contrib.auth.forms import PasswordResetForm +from django.contrib.auth.mixins import LoginRequiredMixin from django.contrib.auth.models import User from django.contrib.auth.tokens import default_token_generator -from django.shortcuts import render, get_list_or_404 +from django.contrib.auth.views import LoginView +from django.core.exceptions import PermissionDenied +from django.http import HttpResponseRedirect +from django.shortcuts import get_list_or_404, redirect, reverse, render from django.urls import reverse_lazy from django.views.generic import FormView -from django_registration.backends.one_step.views import RegistrationView - -from access_controller.settings import EMAIL_HOST_USER -from main.extra_func import check_user_exist, update_profile, get_user_organization, \ - make_engineer, make_light_agent, get_users_list - -from django.contrib.auth.models import User -from main.models import UserProfile -from main.forms import CustomRegistrationForm, AdminPageUsers from django_registration.views import RegistrationView -from django.contrib.auth.decorators import login_required -from django.contrib.auth.mixins import LoginRequiredMixin -from django.core.exceptions import PermissionDenied +from zenpy import Zenpy +from zenpy.lib.api_objects import User as ZenpyUser -import logging - -from access_controller.settings import ZENDESK_ROLES +from access_controller.settings import EMAIL_HOST_USER, ZENDESK_ROLES +from main.extra_func import check_user_exist, update_profile, get_user_organization, make_engineer, make_light_agent, \ + get_users_list +from main.forms import AdminPageUsers, CustomRegistrationForm, CustomAuthenticationForm +from .models import UserProfile class CustomRegistrationView(RegistrationView): @@ -88,12 +87,58 @@ def profile_page(request: UserProfile) -> UserProfile: 'email': user_profile.user.email, 'name': user_profile.name, 'role': user_profile.role, + 'id': user_profile.id, 'image_url': user_profile.image, 'pagename': 'Страница профиля' } return render(request, 'pages/profile.html', context) +def auth_user(request): + admin_creds = { + 'email': os.environ.get('ACCESS_CONTROLLER_API_EMAIL'), + 'subdomain': 'ngenix1612197338', + 'token': os.environ.get('ACCESS_CONTROLLER_API_TOKEN'), + } + admin = Zenpy(**admin_creds) + zenpy_user: ZenpyUser = admin.users.search(request.user.email).values[0] + return zenpy_user, admin + + +@login_required() +def work_page(request, id): + if request.user.id == id: + context = { + 'engineers': UserProfile.objects.filter(role="admin"), + 'agents': UserProfile.objects.filter(role="agent"), + 'pagename': 'Управление правами' + } + return render(request, 'pages/work.html', context) + return redirect("login") + + +@login_required() +def work_hand_over(request): + zenpy_user, admin = auth_user(request) + if zenpy_user.role == "admin" or zenpy_user.role == "end-user": + zenpy_user.role = "agent" + admin.users.update(zenpy_user) + request.user.userprofile.role = "agent" + request.user.userprofile.save() + return HttpResponseRedirect(reverse('work', args=(request.user.id,))) + + +@login_required() +def work_become_engineer(request): + zenpy_user, admin = auth_user(request) + if zenpy_user.role == "agent" or zenpy_user.role == "end-user": + zenpy_user.role = "admin" + admin.users.update(zenpy_user) + request.user.userprofile.role = "admin" + request.user.userprofile.save() + return HttpResponseRedirect(reverse('work', args=(request.user.id,))) + + def main_page(request): """ Отображение логгирования на главной странице @@ -153,3 +198,10 @@ class AdminPageView(FormView, LoginRequiredMixin): UserProfile, role='agent') context['engineers'], context['light_agents'] = self.count_users(get_users_list()) return context # TODO: need to get profile page url + + +class CustomLoginView(LoginView): + """ + Отображение страницы авторизации пользователя + """ + form_class = CustomAuthenticationForm