diff --git a/access_controller/settings.py b/access_controller/settings.py index 8b4ec96..96703b6 100644 --- a/access_controller/settings.py +++ b/access_controller/settings.py @@ -178,3 +178,8 @@ LOGGING = { } } } + +ZENDESK_ROLES = { + 'engineer': 360005209000, + 'light_agent': 360005208980, +} diff --git a/access_controller/urls.py b/access_controller/urls.py index b91e747..45d815b 100644 --- a/access_controller/urls.py +++ b/access_controller/urls.py @@ -18,6 +18,10 @@ 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 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 = [ @@ -27,8 +31,13 @@ urlpatterns = [ path('accounts/register/', CustomRegistrationView.as_view(), name='registration'), 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') ] urlpatterns += [ diff --git a/docs/Makefile b/docs/Makefile index d0c3cbf..461302a 100644 --- a/docs/Makefile +++ b/docs/Makefile @@ -18,3 +18,6 @@ help: # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). %: Makefile @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) + +spelling: + $(SPHINXBUILD) -b spelling -W $(ALLSPHINXOPTS) $(BUILDDIR)/spelling diff --git a/docs/source/conf.py b/docs/source/conf.py index 438d5a4..fdcc4e4 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -12,10 +12,29 @@ # import os import sys +import importlib +import inspect sys.path.insert(0, os.path.abspath('../../')) import django os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'access_controller.settings') +os.environ.setdefault('DJANGO_CONFIGURATION', 'Dev') + +# Fix Django's FileFields +from django.db.models.fields.files import FileDescriptor +FileDescriptor.__get__ = lambda self, *args, **kwargs: self +from django.db.models.manager import ManagerDescriptor +ManagerDescriptor.__get__ = lambda self, *args, **kwargs: self.manager + + +# Stop Django from executing DB queries +from django.db.models.query import QuerySet +QuerySet.__repr__ = lambda self: self.__class__.__name__ +try: + import enchant # NoQA +except ImportError: + enchant = None + django.setup() # -- Project information ----------------------------------------------------- @@ -27,9 +46,82 @@ author = 'SHP S101, group 2' # The full version, including alpha/beta/rc tags release = 'v0.01' +#Django sphinx setup by https://gist.github.com/codingjoe/314bda5a07ff3b41f247 # -- General configuration --------------------------------------------------- +def process_django_models(app, what, name, obj, options, lines): + """Append params from fields to model documentation.""" + from django.utils.encoding import force_text + from django.utils.html import strip_tags + from django.db import models + + spelling_white_list = ['', '.. spelling::'] + + if inspect.isclass(obj) and issubclass(obj, models.Model): + for field in obj._meta.fields: + help_text = strip_tags(force_text(field.help_text)) + verbose_name = force_text(field.verbose_name).capitalize() + + if help_text: + lines.append(':param %s: %s - %s' % (field.attname, verbose_name, help_text)) + else: + lines.append(':param %s: %s' % (field.attname, verbose_name)) + + if enchant is not None: + from enchant.tokenize import basic_tokenize + + words = verbose_name.replace('-', '.').replace('_', '.').split('.') + words = [s for s in words if s != ''] + for word in words: + spelling_white_list += [" %s" % ''.join(i for i in word if not i.isdigit())] + spelling_white_list += [" %s" % w[0] for w in basic_tokenize(word)] + + field_type = type(field) + module = field_type.__module__ + if 'django.db.models' in module: + # scope with django.db.models * imports + module = 'django.db.models' + lines.append(':type %s: %s.%s' % (field.attname, module, field_type.__name__)) + if enchant is not None: + lines += spelling_white_list + print('ok') + return lines + + +def process_modules(app, what, name, obj, options, lines): + """Add module names to spelling white list.""" + if what != 'module': + return lines + from enchant.tokenize import basic_tokenize + + spelling_white_list = ['', '.. spelling::'] + words = name.replace('-', '.').replace('_', '.').split('.') + words = [s for s in words if s != ''] + for word in words: + spelling_white_list += [" %s" % ''.join(i for i in word if not i.isdigit())] + spelling_white_list += [" %s" % w[0] for w in basic_tokenize(word)] + lines += spelling_white_list + return lines + + +def skip_queryset(app, what, name, obj, skip, options): + """Skip queryset subclasses to avoid database queries.""" + from django.db import models + if isinstance(obj, (models.QuerySet, models.manager.BaseManager)) or name.endswith('objects'): + return True + return skip + + +def setup(app): + # Register the docstring processor with sphinx + app.connect('autodoc-process-docstring', process_django_models) + app.connect('autodoc-skip-member', skip_queryset) + if enchant is not None: + app.connect('autodoc-process-docstring', process_modules) + + + # Add any Sphinx extension module names here, as strings. They can be # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom # ones. @@ -39,8 +131,17 @@ extensions = [ 'sphinx.ext.intersphinx', 'sphinx.ext.viewcode', 'sphinx_rtd_theme', + 'sphinx.ext.graphviz', + 'sphinx.ext.napoleon', + 'sphinx.ext.inheritance_diagram', + 'sphinx_autodoc_typehints' + ] +if enchant is not None: + extensions.append('sphinxcontrib.spelling') + + # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] @@ -81,9 +182,27 @@ intersphinx_mapping = { 'https://docs.djangoproject.com/en/dev/', 'https://docs.djangoproject.com/en/dev/_objects/' ), + 'djangoextensions': ('https://django-extensions.readthedocs.org/en/latest/', None), + 'geoposition': ('https://django-geoposition.readthedocs.org/en/latest/', None), + 'braces': ('https://django-braces.readthedocs.org/en/latest/', None), + 'select2': ('https://django-select2.readthedocs.org/en/latest/', None), + 'celery': ('https://celery.readthedocs.org/en/latest/', None), } +autodoc_default_flags = ['members'] + +# spell checking +spelling_lang = 'en_US' +spelling_word_list_filename = 'spelling_wordlist.txt' +spelling_show_suggestions = True +spelling_ignore_pypi_package_names = True + # -- Options for todo extension ---------------------------------------------- # If true, `todo` and `todoList` produce output, else they produce nothing. todo_include_todos = True + +set_type_checking_flag = True +typehints_fully_qualified = True +always_document_param_types = True +typehints_document_rtype = True diff --git a/docs/source/todo.rst b/docs/source/todo.rst index a8d024b..ad6e4ed 100644 --- a/docs/source/todo.rst +++ b/docs/source/todo.rst @@ -1,5 +1,5 @@ Что необходимо доделать? -======================= +======================== diff --git a/main/extra_func.py b/main/extra_func.py index 3ce296a..6227bf1 100644 --- a/main/extra_func.py +++ b/main/extra_func.py @@ -5,27 +5,29 @@ from zenpy.lib.exception import APIException from main.models import UserProfile +from access_controller.settings import ZENDESK_ROLES as ROLES + class ZendeskAdmin: """ Класс **ZendeskAdmin** существует, чтобы в каждой фунциии отдельно не проверять аккаунт администратора :param credentials: Полномочия (первым указывается учетная запись организации в Zendesk) - :type credentials: :class:`list of dictionaries` + :type credentials: :class:`dict` :param email: Email администратора, указанный в env - :type email: :class:`email` + :type email: :class:`str` :param token: Токен администратора (формируется в Zendesk, указывается в env) :type token: :class:`str` :param password: Пароль администратора, указанный в env :type password: :class:`str` """ - credentials = { + credentials: dict = { 'subdomain': 'ngenix1612197338' } - email = os.getenv('ACCESS_CONTROLLER_API_EMAIL') - token = os.getenv('ACCESS_CONTROLLER_API_TOKEN') - password = os.getenv('ACCESS_CONTROLLER_API_PASSWORD') + 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): @@ -38,64 +40,57 @@ class ZendeskAdmin: def check_user(self, email: str) -> bool: """ - Функция **check_user** осуществляет проверку существования пользователя в Zendesk - - :param email: Электронная почта пользователя - :type email: :class:`email` - :return: True, если существует, иначе False - :rtype: :class:`bool` + Функция **check_user** осуществляет проверку существования пользователя в Zendesk по email """ return True if self.admin.search(email, type='user') else False def get_user_name(self, email: str) -> str: """ - Функция **get_user_name** возвращает имя пользователя - - :param user_name: Имя пользователя - :type user_name: :class:`str` + Функция **get_user_name** возвращает имя пользователя по его email """ user = self.admin.users.search(email).values[0] return user.name def get_user_role(self, email: str) -> str: """ - Функция **get_user_role** возвращает роль пользователя - - :param user_role: Роль пользователя - :type user_role: :class:`str` + Функция **get_user_role** возвращает роль пользователя по его email """ user = self.admin.users.search(email).values[0] return user.role def get_user_id(self, email: str) -> str: """ - Функция **get_user_id** возвращает id пользователя - - :param user_id: ID пользователя - :type user_id: :class:`str` + Функция **get_user_id** возвращает id пользователя по его email """ user = self.admin.users.search(email).values[0] return user.id def get_user_image(self, email: str) -> str: """ - Функция **get_user_image** возвращает url-ссылку на аватар пользователя + Функция **get_user_image** возвращает url-ссылку на аватар пользователя по его email """ user = self.admin.users.search(email).values[0] return user.photo['content_url'] if user.photo else None def get_user(self, email: str) -> str: + """ + Функция **get_user** возвращает пользователя (объект) по его email + """ return self.admin.users.search(email).values[0] def get_user_org(self, email: str) -> str: + """ + Функция **get_user_org** возвращает организацию, к которой относится пользователь по его email + """ user = self.admin.users.search(email).values[0] - return user.organization.name + return user.organization.name - def create_admin(self) -> None: + def create_admin(self) -> Zenpy: """ Функция **Create_admin()** создает администратора, проверяя наличие вводимых данных в env. :param credentials: В список полномочий администратора вносятся email, token, password из env + :type credentials: :class:`dict` :raise: :class:`ValueError`: исключение, вызываемое если email не введен в env :raise: :class:`APIException`: исключение, вызываемое если пользователя с таким email не существует в Zendesk """ @@ -117,12 +112,43 @@ class ZendeskAdmin: raise ValueError('invalid access_controller`s login data') -def update_profile(user_profile: UserProfile): +def update_role(user_profile: UserProfile, role: str) -> UserProfile: + """ + Функция **update_role** меняет роль пользователя. + """ + zendesk = ZendeskAdmin() + user = zendesk.get_user(user_profile.user.email) + user.custom_role_id = role + zendesk.admin.users.update(user) + + +def make_engineer(user_profile: UserProfile) -> UserProfile: + """ + Функция **make_engineer** устанавливапет пользователю роль инженера. + """ + update_role(user_profile, ROLES['engineer']) + + +def make_light_agent(user_profile: UserProfile) -> UserProfile: + """ + Функция **make_light_agent** устанавливапет пользователю роль легкого агента. + """ + update_role(user_profile, ROLES['light_agent']) + + +def get_users_list() -> list: + """ + Функция **get_users_list** возвращает список пользователей Zendesk, относящихся к организации. + """ + zendesk = ZendeskAdmin() + admin = zendesk.get_user(zendesk.email) + org = next(zendesk.admin.users.organizations(user=admin)) + return zendesk.admin.organizations.users(org) + + +def update_profile(user_profile: UserProfile) -> UserProfile: """ Функция обновляет профиль пользователя в соотвтетствии с текущим в Zendesk - - :param user_profile: Объект профиля пользователя - :type user_profile: :class:`main.models.UserProfile` """ user = ZendeskAdmin().get_user(user_profile.user.email) user_profile.name = user.name @@ -133,12 +159,7 @@ def update_profile(user_profile: UserProfile): def check_user_exist(email: str) -> bool: """ - Функция проверяет, существует ли пользователь - - :param email: Электронная почта пользователя - :type email: :class:`str` - :return: True, если существует, иначе False - :rtype: :class:`bool` + Функция проверяет, существует ли пользователь """ return ZendeskAdmin().check_user(email) @@ -146,11 +167,6 @@ def check_user_exist(email: str) -> bool: def get_user_organization(email: str) -> str: """ Функция возвращает организацию пользователя - - :param email: Электронная почта пользователя - :type email: :class:`str` - :return: Название организации - :rtype: :class:`str` """ return ZendeskAdmin().get_user_org(email) @@ -159,13 +175,7 @@ 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: :class:`APIException`: исключение, вызываемое если пользователь не аутентифицирован - :rtype: :class:`bool` """ creds = { 'email': email, diff --git a/main/forms.py b/main/forms.py index e33e1ae..e69de1d 100644 --- a/main/forms.py +++ b/main/forms.py @@ -2,6 +2,8 @@ from django import forms from django.contrib.auth.forms import AuthenticationForm from django_registration.forms import RegistrationFormUniqueEmail +from main.models import UserProfile + class CustomRegistrationForm(RegistrationFormUniqueEmail): """ @@ -23,6 +25,22 @@ class CustomRegistrationForm(RegistrationFormUniqueEmail): fields = RegistrationFormUniqueEmail.Meta.fields +class AdminPageUsers(forms.Form): + """ + Форма для установки статуса + """ + + users = forms.ModelMultipleChoiceField( + queryset=UserProfile.objects.filter(role='agent'), + widget=forms.CheckboxSelectMultiple( + attrs={ + 'class': 'form-check-input' + } + ), + label='' + ) + + class CustomAuthenticationForm(AuthenticationForm): """ Форма для авторизации :class:`django.contrib.auth.forms.AuthenticationForm` diff --git a/main/models.py b/main/models.py index 3e3fe29..8665570 100644 --- a/main/models.py +++ b/main/models.py @@ -1,5 +1,5 @@ -from django.contrib.auth.models import User from django.db import models +from django.contrib.auth.models import User from django.db.models.signals import post_save from django.dispatch import receiver @@ -8,19 +8,12 @@ class UserProfile(models.Model): """ Модель профиля пользователя - :param user: OneToOneField к модели :class:`django.contrib.auth.models.User` - :param role: Код роли пользователя - :type role: :class:`integer` - :param image: Аватарка - :type image: :class:`img` - :param name: Имя пользователя на нашем сайте - :type name: :class:`str` """ - user = models.OneToOneField(to=User, on_delete=models.CASCADE) - role = models.CharField(default='None', max_length=100) - image = models.URLField(null=True, blank=True) - name = models.CharField(default='None', max_length=100) + user = models.OneToOneField(to=User, on_delete=models.CASCADE, help_text='Пользователь') + role = models.CharField(default='None', max_length=100, help_text='Код роли пользователя') + image = models.URLField(null=True, blank=True, help_text='Аватарка') + name = models.CharField(default='None', max_length=100, help_text='Имя пользователя на нашем сайте') @receiver(post_save, sender=User) @@ -38,17 +31,9 @@ class RoleChangeLogs(models.Model): """ Модель для логирования изменений ролей пользователя - :param user: Пользователь, которому присвоили другую роль, ForeignKey к модели :class:`django.contrib.auth.models.User` - :param name: Имя пользователя - :type name: :class:`str` - :param new_role: Присвоенная роль - :type new_role: :class:`str` - :param change_time: Дата изменения роли` - :type change_time: :class:`datetime.datetime` - :param changed_by: Кем была изменена роль, ForeignKey к модели :class:`django.contrib.auth.models.User` """ - user = models.ForeignKey(to=User, on_delete=models.CASCADE) - name = models.TextField() - new_role = models.TextField() - change_time = models.DateTimeField() - changed_by = models.ForeignKey(to=User, on_delete=models.CASCADE, related_name='changed_by') + user = models.ForeignKey(to=User, on_delete=models.CASCADE, help_text='Пользователь, которому присвоили другую роль') + name = models.TextField(help_text='Имя пользователя') + new_role = models.TextField(help_text='Присвоенная роль') + change_time = models.DateTimeField(help_text='Дата и время изменения роли') + changed_by = models.ForeignKey(to=User, on_delete=models.CASCADE, related_name='changed_by', help_text='Кем была изменена роль') diff --git a/main/templates/pages/adm_ruleset.html b/main/templates/pages/adm_ruleset.html index a2e3e9d..1bddc5f 100644 --- a/main/templates/pages/adm_ruleset.html +++ b/main/templates/pages/adm_ruleset.html @@ -2,76 +2,108 @@ {% load static %} -{% block title %}{{ pagename }}{% endblock %} +{% block title %}Управление{%endblock %} {% block heading %}Управление{% endblock %} {% block extra_css %} - + {% endblock %} {% block content %}
+
+

Основная информация о странице

+
-
-

Основаная информация о странице

+
+ {% csrf_token %} + +
+ +
+ {% for field in form.users %} + {{ field.tag }} + {% endfor %} +
+ +
+
Список сотрудников
+ + + + + + + + + + + + {% for user in users %} + + + + + + + + {% endfor %} + + +
IDEmailRoleName(link to profile)Checked
{{ user.id }}{{ user.user.email }}{{ user.role }}{{ user.name }}
+ +
-
-
Список сотрудников
- - - - - - - - - - - - - - - - - - - - - - - - - -
IDEmailRoleName(link to profile)Checked
1big_boss123@example.ruengineerИван Иванов
2gachi_cool456@example.rulight engineerПётр Петров
-
-
-
-
-
-
-
Инженеров:
-
-
- 13 -
-
-
-
Легких агентов:
-
-
- 22 -
- -
+
+
+ +
+
Инженеров:
+
+
+ {{ engineers }}
+
+ +
+
Легких агентов:
+
+
+ {{ light_agents }} +
+
+
-
- - -
+
+ +
+ + + + + +
+
-{% endblock %} \ No newline at end of file + + + +{% endblock %} 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/templates/registration/login.html b/main/templates/registration/login.html index 9bb5175..7a3ab68 100644 --- a/main/templates/registration/login.html +++ b/main/templates/registration/login.html @@ -1,10 +1,9 @@ {% extends 'base/base.html' %} -{% block title %} - Авторизация -{% endblock %} -{% block heading %} - Авторизация -{% endblock %} + +{% block title %}Авторизация{% endblock %} + +{% block heading %}Авторизация{% endblock %} + {% block content %}
diff --git a/main/views.py b/main/views.py index 8fb892a..b765bd0 100644 --- a/main/views.py +++ b/main/views.py @@ -1,17 +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.contrib.auth.views import LoginView -from django.shortcuts import render +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.views import RegistrationView +from zenpy import Zenpy +from zenpy.lib.api_objects import User as ZenpyUser -from access_controller.settings import EMAIL_HOST_USER -from main.extra_func import check_user_exist, update_profile, get_user_organization -from main.forms import CustomRegistrationForm, CustomAuthenticationForm +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): @@ -78,18 +87,104 @@ def profile_page(request): '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): logger = logging.getLogger('main.index') logger.info('Index page opened') return render(request, 'pages/index.html') +class AdminPageView(FormView, LoginRequiredMixin): + template_name = 'pages/adm_ruleset.html' + form_class = AdminPageUsers + success_url = '/control/' + + def form_valid(self, form): + if 'engineer' in self.request.POST: + self.make_engineers(form.cleaned_data['users']) + elif 'light_agent' in self.request.POST: + self.make_light_agents(form.cleaned_data['users']) + return super().form_valid(form) + + @staticmethod + def make_engineers(users): + [make_engineer(user) for user in users] + + @staticmethod + def make_light_agents(users): + [make_light_agent(user) for user in users] + + @staticmethod + def count_users(users): # TODO: this func counts users from all zendesk instead of just from a model + engineers, light_agents = 0, 0 + for user in users: + if user.custom_role_id == ZENDESK_ROLES['engineer']: + engineers += 1 + elif user.custom_role_id == ZENDESK_ROLES['light_agent']: + light_agents += 1 + return engineers, light_agents + + def get_context_data(self, **kwargs): + if self.request.user.userprofile.role != 'admin': + raise PermissionDenied + context = super().get_context_data(**kwargs) + context['users'] = get_list_or_404( + 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): """ Отображение страницы авторизации пользователя