Merge branch 'feature/documentation' into 'develop'
Feature/documentation See merge request 2020-2021/online/s101/group-02/access_controller!89
This commit is contained in:
commit
385d75de3e
19
README.md
19
README.md
@ -149,25 +149,22 @@ docker run -d -p 8000:8000 \
|
||||
Пример полной конфигурации можно найти в [.env.example](.env.example). Почту и токен админа ZenDesk взять у руководителя (если вы не админ).
|
||||
|
||||
## Для проверки pylint используем:
|
||||
```bash
|
||||
pylint --django-settings-module=access_controller.settings main
|
||||
```
|
||||
pylint --django-settings-module=access_controller.access_controller.settings ../access_controller (каталог, где лежит проект)
|
||||
|
||||
## Для приведения файлов к стандарту PEP8 используем:
|
||||
```bash
|
||||
autopep8 --in-place filename
|
||||
```
|
||||
|
||||
##Для проверки орфографии:
|
||||
```bash
|
||||
(cd docs && make spelling)
|
||||
```
|
||||
cd docs
|
||||
|
||||
make spelling
|
||||
##Для обновления документации:
|
||||
```bash
|
||||
m2r README.md
|
||||
(cd docs && make html)
|
||||
```
|
||||
|
||||
cd docs
|
||||
|
||||
make html
|
||||
|
||||
|
||||
## Read more
|
||||
- Zenpy: [http://docs.facetoe.com.au](http://docs.facetoe.com.au)
|
||||
|
17
README.rst
17
README.rst
@ -57,9 +57,9 @@ Quickstart
|
||||
sudo apt install make
|
||||
pip install --upgrade pip
|
||||
pip install -r requirements/dev.txt
|
||||
(set -a && source .env && ./manage.py migrate)
|
||||
(set -a && source .env && ./manage.py loaddata data.json)
|
||||
(set -a && source .env && ./manage.py runserver)
|
||||
./manage.py migrate
|
||||
./manage.py loaddata data.json
|
||||
./manage.py runserver
|
||||
|
||||
Перед запуском для тестирования:
|
||||
--------------------------------
|
||||
@ -76,7 +76,7 @@ Quickstart
|
||||
* Перейти в папку приложения
|
||||
* Активировать виртуальное окружение
|
||||
* Выполнить команду ``pip install -r requirements/dev.txt``
|
||||
* В виртуальное окружение добавить следующие переменные:
|
||||
* В файл ``.env`` добавить следующие переменные:
|
||||
|
||||
.. code-block::
|
||||
|
||||
@ -170,10 +170,7 @@ Quickstart
|
||||
Для проверки pylint используем:
|
||||
-------------------------------
|
||||
|
||||
pylint ../access_controller_new
|
||||
|
||||
Вместо "access_controller_new" необходимо указать папку проекта.
|
||||
|
||||
pylint ../access_controller (каталог, где лежит проект)
|
||||
|
||||
Для приведения файлов к стандарту PEP8 используем:
|
||||
--------------------------------------------------
|
||||
@ -185,7 +182,7 @@ autopep8 --in-place filename
|
||||
|
||||
cd docs
|
||||
|
||||
(set -a && source ../.env && make spelling)
|
||||
make spelling
|
||||
|
||||
Для обновления документации:
|
||||
----------------------------
|
||||
@ -194,7 +191,7 @@ m2r README.md
|
||||
|
||||
cd docs
|
||||
|
||||
(set -a && source ../.env && make html)
|
||||
make html
|
||||
|
||||
Read more
|
||||
---------
|
||||
|
@ -10,6 +10,7 @@ For the full list of settings and their values, see
|
||||
https://docs.djangoproject.com/en/3.1/ref/settings/
|
||||
"""
|
||||
import os
|
||||
|
||||
from pathlib import Path
|
||||
from dotenv import load_dotenv
|
||||
|
||||
|
BIN
docs/source/_static/statistic.png
Normal file
BIN
docs/source/_static/statistic.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 91 KiB |
BIN
docs/source/_static/take_tickets.png
Normal file
BIN
docs/source/_static/take_tickets.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 72 KiB |
@ -41,3 +41,33 @@ Views
|
||||
:members:
|
||||
|
||||
|
||||
*****************
|
||||
Обработка тикетов
|
||||
*****************
|
||||
|
||||
.. automodule:: main.requester
|
||||
:members:
|
||||
|
||||
|
||||
*********************
|
||||
Обработка статистики
|
||||
*********************
|
||||
|
||||
.. automodule:: main.statistic_data
|
||||
:members:
|
||||
|
||||
|
||||
*********************************
|
||||
Функционал администратора Zendesk
|
||||
*********************************
|
||||
|
||||
.. automodule:: main.zendesk_admin
|
||||
:members:
|
||||
|
||||
|
||||
********
|
||||
Тесты
|
||||
********
|
||||
|
||||
.. automodule:: main.tests
|
||||
:members:
|
||||
|
@ -81,6 +81,12 @@
|
||||
|
||||
.. image:: _static/role_change.png
|
||||
|
||||
Являясь инженером, Вы можете запросить в работу необходимое количество тикетов.
|
||||
|
||||
.. image:: _static/take_tickets.png
|
||||
|
||||
Назначенные тикеты будут доступны в Zendesk.
|
||||
|
||||
******************************************
|
||||
Управление правами доступа администратором
|
||||
******************************************
|
||||
@ -97,4 +103,13 @@
|
||||
|
||||
.. image:: _static/admin_manage_done.png
|
||||
|
||||
.. |copy| unicode:: 0xA9 .. Школа программистов S101, группа 2. 2021гю
|
||||
Вы можете смотреть статистику работы пользователя.
|
||||
Для этого на странице статистика необходимо указать:
|
||||
|
||||
* email пользователя
|
||||
* период, за который необходима статистика
|
||||
* формат отображения данных
|
||||
|
||||
.. image:: _static/statistic.png
|
||||
|
||||
.. |copy| unicode:: 0xA9 .. Школа программистов S101, группа 2. 2021г.
|
||||
|
@ -191,4 +191,58 @@ docs
|
||||
a
|
||||
Аватарка
|
||||
filename
|
||||
|
||||
work
|
||||
form
|
||||
work_get_tickets
|
||||
get
|
||||
tickets
|
||||
Do
|
||||
takes
|
||||
whatever
|
||||
it
|
||||
to
|
||||
actually
|
||||
log
|
||||
the
|
||||
specified
|
||||
logging
|
||||
record
|
||||
This
|
||||
version
|
||||
is
|
||||
intended
|
||||
be
|
||||
implemented
|
||||
by
|
||||
subclasses
|
||||
so
|
||||
new
|
||||
тикеты
|
||||
StatisticForm
|
||||
patch
|
||||
zenpy
|
||||
Mock
|
||||
редирект
|
||||
редиректа
|
||||
предустановки
|
||||
TicketListRequester
|
||||
get_tickets_list_for_user
|
||||
side
|
||||
effect
|
||||
for
|
||||
залогиненный
|
||||
предустанавливает
|
||||
переадресация
|
||||
фикстуры
|
||||
profile
|
||||
json
|
||||
аватарки
|
||||
аватарке
|
||||
locmem
|
||||
бэкенд
|
||||
has
|
||||
control
|
||||
disallowed
|
||||
test
|
||||
users
|
||||
Contents
|
||||
|
@ -1,9 +1,9 @@
|
||||
"""
|
||||
Вспомогательные функции со списками пользователей, статистикой и т.д.
|
||||
Вспомогательные функции.
|
||||
"""
|
||||
import logging
|
||||
from datetime import timedelta
|
||||
from typing import Union
|
||||
from datetime import timedelta, date
|
||||
from typing import Union, Optional
|
||||
|
||||
from django.contrib.auth import get_user_model
|
||||
from django.core.exceptions import ObjectDoesNotExist
|
||||
@ -29,7 +29,6 @@ def update_role(user_profile: UserProfile, role: int, who_changes: get_user_mode
|
||||
:param user_profile: Профиль пользователя
|
||||
:param role: Новая роль
|
||||
:param who_changes: Пользователь, меняющий роль
|
||||
:return: Пользователь с обновленной ролью
|
||||
"""
|
||||
zendesk = zenpy
|
||||
user = zendesk.get_user(user_profile.user.email)
|
||||
@ -55,7 +54,8 @@ def make_light_agent(user_profile: UserProfile, who_changes: get_user_model()) -
|
||||
Функция устанавливает пользователю роль легкого агента.
|
||||
|
||||
:param user_profile: Профиль пользователя
|
||||
:return: Вызов функции **update_role** с параметрами: профиль пользователя, роль "light_agent"
|
||||
:return: Вызов функции **update_role** с параметрами: профиль пользователя, роль "light_agent".
|
||||
Предварительно снимаем тикеты, находящие в работы у пользователя.
|
||||
"""
|
||||
tickets: SearchResultGenerator = get_tickets_list(user_profile.user.email)
|
||||
ticket: ZenpyTicket
|
||||
@ -85,7 +85,7 @@ def make_light_agent(user_profile: UserProfile, who_changes: get_user_model()) -
|
||||
|
||||
def get_users_list() -> list:
|
||||
"""
|
||||
Функция **get_users_list** возвращает список пользователей Zendesk, относящихся к организации SYSTEM.
|
||||
Функция возвращает список пользователей Zendesk, относящихся к организации SYSTEM.
|
||||
"""
|
||||
zendesk = zenpy
|
||||
|
||||
@ -95,23 +95,29 @@ def get_users_list() -> list:
|
||||
return users
|
||||
|
||||
|
||||
def get_tickets_list(email) -> list:
|
||||
def get_tickets_list(email: str) -> Optional[list]:
|
||||
"""
|
||||
Функция возвращает список тикетов пользователя Zendesk
|
||||
Функция возвращает список тикетов пользователя Zendesk.
|
||||
|
||||
:param email: Email пользователя
|
||||
:return: Список тикетов пользователя
|
||||
"""
|
||||
return TicketListRequester().get_tickets_list_for_user(zenpy.get_user(email))
|
||||
|
||||
|
||||
def get_tickets_list_for_group(group_name):
|
||||
def get_tickets_list_for_group(group_name: str) -> Optional[list]:
|
||||
"""
|
||||
Функция возвращает список неназначенных, нерешённых тикетов группы Zendesk
|
||||
Функция возвращает список не назначенных, не решённых тикетов группы Zendesk.
|
||||
|
||||
:param group_name: Название группы пользователя
|
||||
:return: Список тикетов группы
|
||||
"""
|
||||
return TicketListRequester().get_tickets_list_for_group(zenpy.get_group(group_name))
|
||||
|
||||
|
||||
def update_profile(user_profile: UserProfile) -> None:
|
||||
"""
|
||||
Функция обновляет профиль пользователя в соответствии с текущим в Zendesk.
|
||||
Функция обновляет профиль пользователя в БД в соответствии с текущим в Zendesk.
|
||||
|
||||
:param user_profile: Профиль пользователя
|
||||
:return: Обновленный, в соответствие с текущими данными в Zendesk, профиль пользователя
|
||||
@ -148,6 +154,9 @@ def check_user_auth(email: str, password: str) -> bool:
|
||||
"""
|
||||
Функция проверяет, верны ли входные данные.
|
||||
|
||||
:param email: Email пользователя
|
||||
:param password: Пароль пользователя
|
||||
:return: Существует ли пользователь
|
||||
:raise: :class:`APIException`: исключение, вызываемое если пользователь не аутентифицирован
|
||||
"""
|
||||
creds = {
|
||||
@ -165,7 +174,7 @@ def check_user_auth(email: str, password: str) -> bool:
|
||||
|
||||
def update_user_in_model(profile: UserProfile, zendesk_user: ZenpyUser) -> None:
|
||||
"""
|
||||
Функция обновляет профиль пользователя при изменении данных пользователя на Zendesk.
|
||||
Функция обновляет профиль пользователя в модели при изменении данных пользователя на Zendesk.
|
||||
|
||||
:param profile: Профиль пользователя
|
||||
:param zendesk_user: Данные пользователя в Zendesk
|
||||
@ -181,7 +190,10 @@ def update_user_in_model(profile: UserProfile, zendesk_user: ZenpyUser) -> None:
|
||||
|
||||
def count_users(users: list) -> tuple:
|
||||
"""
|
||||
Функция подсчета количества сотрудников с ролями engineer и light_agent
|
||||
Функция подсчета количества сотрудников с ролями engineer и light_agent.
|
||||
|
||||
:param users: Список пользователей
|
||||
:return: Количество инженеров, количество light_agents
|
||||
"""
|
||||
engineers, light_agents = 0, 0
|
||||
for user in users:
|
||||
@ -194,7 +206,7 @@ def count_users(users: list) -> tuple:
|
||||
|
||||
def update_users_in_model() -> list:
|
||||
"""
|
||||
Обновляет пользователей в модели UserProfile по списку пользователей в организации
|
||||
Обновляет пользователей в модели UserProfile по списку пользователей в организации.
|
||||
"""
|
||||
users = get_users_list()
|
||||
for user in users:
|
||||
@ -206,7 +218,7 @@ def update_users_in_model() -> list:
|
||||
return users
|
||||
|
||||
|
||||
def daterange(start_date: timedelta, end_date: timedelta) -> list:
|
||||
def daterange(start_date: date, end_date: date) -> list:
|
||||
"""
|
||||
Функция возвращает список дней с start_date по end_date, исключая правую границу.
|
||||
|
||||
@ -253,7 +265,13 @@ class DatabaseHandler(logging.Handler):
|
||||
def __init__(self):
|
||||
logging.Handler.__init__(self)
|
||||
|
||||
def emit(self, record):
|
||||
def emit(self, record: logging.LogRecord) -> None:
|
||||
"""
|
||||
Функция записи в базу данных лога с изменением роли пользователя.
|
||||
|
||||
:param record: Лог смены роли пользователя
|
||||
:return: Запись в БД лога по смене роли пользователя с указанием новой и старой роли, а также автора изменения
|
||||
"""
|
||||
database = RoleChangeLogs()
|
||||
users = record.msg
|
||||
if users[1]:
|
||||
@ -284,7 +302,7 @@ class CsvFormatter(logging.Formatter):
|
||||
"""
|
||||
Функция форматирует запись смены роли пользователя в строку.
|
||||
|
||||
:param record: Запись смены роли пользователя.
|
||||
:param record: Лог смены роли пользователя.
|
||||
:return: Строка с записью смены пользователя.
|
||||
"""
|
||||
users = record.msg
|
||||
@ -307,7 +325,7 @@ class CsvFormatter(logging.Formatter):
|
||||
return msg
|
||||
|
||||
|
||||
def log(user, admin=None):
|
||||
def log(user: get_user_model(), admin: get_user_model() = None) -> None:
|
||||
"""
|
||||
Функция осуществляет запись логов в базу данных и csv файл.
|
||||
|
||||
@ -335,7 +353,7 @@ def set_session_params_for_work_page(request: WSGIRequest, count: int = None, is
|
||||
|
||||
:param request: Получение данных с рабочей страницы пользователя
|
||||
:param count: Количество запрошенных тикетов
|
||||
:param is_confirm: Назначение тикетов
|
||||
:param is_confirm: Назначены ли тикеты
|
||||
:return: Перезагрузка страницы "Управление правами" соответствующего пользователя
|
||||
"""
|
||||
request.session['is_confirm'] = is_confirm
|
||||
|
@ -1,5 +1,5 @@
|
||||
"""
|
||||
Формы.
|
||||
Формы, использующиеся в приложении.
|
||||
"""
|
||||
from django import forms
|
||||
from django.contrib.auth.forms import AuthenticationForm
|
||||
|
@ -13,7 +13,6 @@ from access_controller.settings import ZENDESK_ROLES
|
||||
class UserProfile(models.Model):
|
||||
"""
|
||||
Модель профиля пользователя.
|
||||
|
||||
Профиль создается и изменяется при создании и изменении модель User.
|
||||
"""
|
||||
|
||||
@ -31,11 +30,7 @@ class UserProfile(models.Model):
|
||||
@property
|
||||
def zendesk_role(self) -> str:
|
||||
"""
|
||||
Функция возвращает роль пользователя в Zendesk.
|
||||
|
||||
В формате str, либо UNDEFINED, если пользователь не найден
|
||||
|
||||
:return: Роль пользователя в Zendesk
|
||||
Роль пользователя в Zendesk, либо UNDEFINED, если пользователь не найден.
|
||||
"""
|
||||
for role, r_id in ZENDESK_ROLES.items():
|
||||
if r_id == self.custom_role_id:
|
||||
@ -44,12 +39,12 @@ class UserProfile(models.Model):
|
||||
|
||||
|
||||
@receiver(post_save, sender=get_user_model())
|
||||
def create_user_profile(instance, created, **kwargs) -> None:
|
||||
def create_user_profile(instance: get_user_model(), created: bool, **kwargs) -> None:
|
||||
"""
|
||||
Функция создания профиля пользователя (Userprofile) при регистрации пользователя.
|
||||
|
||||
:param instance: Экземпляр класса User
|
||||
:param created: Создание профиля пользователя
|
||||
:param created: Существует ли пользователь
|
||||
:param kwargs: Параметры
|
||||
:return: Обновленный список объектов профилей пользователей
|
||||
"""
|
||||
@ -58,7 +53,7 @@ def create_user_profile(instance, created, **kwargs) -> None:
|
||||
|
||||
|
||||
@receiver(post_save, sender=get_user_model())
|
||||
def save_user_profile(instance, **kwargs) -> None:
|
||||
def save_user_profile(instance: get_user_model(), **kwargs) -> None:
|
||||
"""
|
||||
Функция записи БД профиля пользователя.
|
||||
|
||||
@ -84,7 +79,7 @@ class RoleChangeLogs(models.Model):
|
||||
|
||||
class UnassignedTicketStatus(models.IntegerChoices):
|
||||
"""
|
||||
Класс статусов не распределенных тикетов.
|
||||
Модель статусов не распределенных тикетов.
|
||||
|
||||
:param UNASSIGNED: Снят с пользователя, перенесён в буферную группу
|
||||
:param RESTORED: Авторство восстановлено
|
||||
@ -95,7 +90,7 @@ class UnassignedTicketStatus(models.IntegerChoices):
|
||||
"""
|
||||
UNASSIGNED = 0, 'Снят с пользователя, перенесён в буферную группу'
|
||||
RESTORED = 1, 'Авторство восстановлено'
|
||||
NOT_FOUND = 2, 'Пока нас не было, тикет испарился из ' \
|
||||
NOT_FOUND = 2, 'Пока нас не было, тикет был перенесен из ' \
|
||||
'буферной группы. Дополнительные действия не требуются'
|
||||
CLOSED = 3, 'Тикет уже был закрыт. Дополнительные действия не требуются'
|
||||
SOLVED = 4, 'Тикет решён. Записан на пользователя с почтой SOLVED_TICKETS_EMAIL'
|
||||
|
@ -1,6 +1,8 @@
|
||||
"""
|
||||
Обработка тикетов.
|
||||
Обработка тикетов, составление списков тикетов для пользователя и группы пользователей.
|
||||
"""
|
||||
from typing import Optional
|
||||
|
||||
import requests
|
||||
from zenpy import TicketApi
|
||||
from zenpy.lib.api_objects import Ticket
|
||||
@ -11,6 +13,13 @@ from main.zendesk_admin import zenpy
|
||||
class TicketListRequester:
|
||||
"""
|
||||
Класс обработки тикетов.
|
||||
|
||||
:param email: Email пользователя
|
||||
:type display: :class:`str`
|
||||
:param token_or_password: Токен или пароль
|
||||
:type display: :class:`str`
|
||||
:param prefix: Формат строка url страницы Zendesk
|
||||
:type display: :class:`str`
|
||||
"""
|
||||
def __init__(self):
|
||||
self.email = zenpy.credentials['email']
|
||||
@ -21,16 +30,22 @@ class TicketListRequester:
|
||||
self.token_or_password = zenpy.credentials.get('password')
|
||||
self.prefix = f'https://{zenpy.credentials.get("subdomain")}.zendesk.com/api/v2/'
|
||||
|
||||
def get_tickets_list_for_user(self, zendesk_user: zenpy) -> str:
|
||||
def get_tickets_list_for_user(self, zendesk_user: zenpy) -> Optional[list]:
|
||||
"""
|
||||
Функция получения списка тикетов пользователя Zendesk.
|
||||
|
||||
:param zendesk_user: Пользователь Zendesk
|
||||
:return: Список тикетов, назначенных на данного пользователя в Zendesk
|
||||
"""
|
||||
url = self.prefix + f'users/{zendesk_user.id}/tickets/assigned'
|
||||
return self._get_tickets(url)
|
||||
|
||||
def get_tickets_list_for_group(self, group: zenpy) -> list():
|
||||
def get_tickets_list_for_group(self, group: zenpy) -> Optional[list]:
|
||||
"""
|
||||
Функция получения списка тикетов группы пользователей Zendesk.
|
||||
|
||||
:param group: Название группы
|
||||
:return: Список тикетов
|
||||
"""
|
||||
url = self.prefix + '/tickets'
|
||||
all_tickets = self._get_tickets(url)
|
||||
@ -40,9 +55,12 @@ class TicketListRequester:
|
||||
tickets.append(ticket)
|
||||
return tickets
|
||||
|
||||
def _get_tickets(self, url: str) -> list():
|
||||
def _get_tickets(self, url: str) -> Optional[list]:
|
||||
"""
|
||||
Функция получения полного списка тикетов по url.
|
||||
|
||||
:param url: Url Zendesk c указанием тикетов, назначенных на пользователя
|
||||
:return: Список тикетов
|
||||
"""
|
||||
response = requests.get(url, auth=(self.email, self.token_or_password))
|
||||
tickets = []
|
||||
|
@ -1,5 +1,5 @@
|
||||
"""
|
||||
Сериализаторы.
|
||||
Сериализаторы, используемые в приложении.
|
||||
"""
|
||||
from django.contrib.auth import get_user_model
|
||||
from rest_framework import serializers
|
||||
|
@ -1,6 +1,9 @@
|
||||
"""
|
||||
Обработка статистики.
|
||||
|
||||
Обнаруживает факт изменения роли пользователя и вычисляет отработанное на смене время.
|
||||
"""
|
||||
|
||||
from datetime import date, datetime, timedelta
|
||||
from typing import Optional
|
||||
|
||||
@ -14,7 +17,7 @@ from main.models import RoleChangeLogs
|
||||
|
||||
class StatisticData:
|
||||
"""
|
||||
Класс для учета статистики интервалов работы пользователей.
|
||||
Класс для учета статистики времени работы пользователей.
|
||||
Передаваемые параметры: start_date, end_date, email, stat.
|
||||
|
||||
:param display: Формат отображения времени (часы, минуты)
|
||||
@ -37,7 +40,7 @@ class StatisticData:
|
||||
:type statistic: :class:`dict`
|
||||
"""
|
||||
|
||||
def __init__(self, start_date, end_date, user_email, stat=None):
|
||||
def __init__(self, start_date, end_date, user_email: str, stat=None):
|
||||
self.display = None
|
||||
self.interval = None
|
||||
self.start_date = start_date
|
||||
@ -57,7 +60,8 @@ class StatisticData:
|
||||
"""
|
||||
Функция возвращает статистику работы пользователя.
|
||||
|
||||
:return: Словарь statistic с применением формата отображения и интервала работы(если они есть).
|
||||
:return: Словарь statistic с применением формата отображения
|
||||
и интервала работы (если они есть).
|
||||
None, если были ошибки при создании.
|
||||
"""
|
||||
if self.is_valid_statistic():
|
||||
@ -117,7 +121,7 @@ class StatisticData:
|
||||
"""
|
||||
return not self.errors
|
||||
|
||||
def _use_display(self, stat: list) -> list:
|
||||
def _use_display(self, stat: dict) -> dict:
|
||||
"""
|
||||
Функция приводит данные к формату отображения.
|
||||
|
||||
@ -136,7 +140,9 @@ class StatisticData:
|
||||
|
||||
def _use_interval(self, stat: dict) -> dict:
|
||||
"""
|
||||
Функция объединяет ключи и значения в соответствии с интервалом работы.
|
||||
Переупаковка результата в соответствии с указанным временным диапазоном
|
||||
|
||||
Сжимает набор дней в месяцы, если указан режим работы "по месяцам"
|
||||
|
||||
:param stat: Статистика работы пользователя
|
||||
:return: Обновленная статистика
|
||||
@ -172,8 +178,8 @@ class StatisticData:
|
||||
"""
|
||||
Функция возвращает логи в диапазоне дат start_date - end_date для пользователя с указанным email.
|
||||
|
||||
:return: Данные о смене статусов пользователя. Если пользователь не найден или
|
||||
интервал времени некорректен - ошибку.
|
||||
:return: Данные о смене статусов пользователя.
|
||||
Если пользователь не найден или интервал времени некорректен - ошибку.
|
||||
"""
|
||||
if not self.check_time():
|
||||
self.errors += ['Конец диапазона должен быть позже начала диапазона и раньше текущего времени']
|
||||
@ -208,9 +214,12 @@ class StatisticData:
|
||||
if self.data[log_index].new_role == ROLES['engineer']:
|
||||
self.engineer_logic(log_index)
|
||||
|
||||
def engineer_logic(self, log_index):
|
||||
def engineer_logic(self, log_index: int) -> None:
|
||||
"""
|
||||
Функция обрабатывает основную часть работы инженера
|
||||
Функция вычисляет время работы инженера.
|
||||
|
||||
:param log_index: Индекс текущего лога
|
||||
:return: Дополняет статистику работы инженера временем между текущим и последующим логом
|
||||
"""
|
||||
current_log, next_log = self.data[log_index], self.data[log_index + 1]
|
||||
if current_log.change_time.date() != next_log.change_time.date():
|
||||
@ -222,9 +231,14 @@ class StatisticData:
|
||||
elapsed_time = next_log.change_time - current_log.change_time
|
||||
self.statistic[current_log.change_time.date()] += elapsed_time.total_seconds()
|
||||
|
||||
def post_engineer_logic(self, last_log):
|
||||
def post_engineer_logic(self, last_log: RoleChangeLogs) -> None:
|
||||
"""
|
||||
Функция обрабатывает случай, когда нам изветсно что инженер работал и после диапазона
|
||||
Обработка случая, в котором инженер не закрыл смену.
|
||||
|
||||
В таком случае считается всё время от момента открытия смены до текущего момента.
|
||||
|
||||
:param last_log: Последний лог изменения роли, в результате которого пользователь назначен инженером.
|
||||
:return: Дополняет статистику работы
|
||||
"""
|
||||
self.fill_daterange(last_log.change_time.date() + timedelta(days=1), self.end_date + timedelta(days=1))
|
||||
if last_log.change_time.date() == timezone.now().date():
|
||||
@ -237,15 +251,25 @@ class StatisticData:
|
||||
if self.end_date == timezone.now().date():
|
||||
self.statistic[self.end_date] = get_timedelta(None, timezone.now().time()).total_seconds()
|
||||
|
||||
def prev_engineer_logic(self, first_log):
|
||||
def prev_engineer_logic(self, first_log: RoleChangeLogs) -> None:
|
||||
"""
|
||||
Функция обрабатывает случай, когда нам изветсно что инженер начал работу до диапазона
|
||||
Обработка случая, в котором инженер закрыл смену в отражаемом периоде, а открыл её до этого периода.
|
||||
|
||||
В таком случае должен быть учтён только период от начала отображаемого диапазона до закрытия смены.
|
||||
|
||||
:param first_log_log: Первый лог в диапазоне, в результате которого пользователь назначен легким агентом.
|
||||
:return: Дополняет статистику работы
|
||||
"""
|
||||
self.fill_daterange(max(get_user_model().objects.get(email=self.email).date_joined.date(), self.start_date),
|
||||
first_log.change_time.date())
|
||||
self.fill_daterange(
|
||||
max(
|
||||
get_user_model().objects.get(email=self.email).date_joined.date(),
|
||||
self.start_date
|
||||
),
|
||||
first_log.change_time.date()
|
||||
)
|
||||
self.statistic[first_log.change_time.date()] += get_timedelta(first_log).total_seconds()
|
||||
|
||||
def fill_daterange(self, first: date, last: date, val: int = 24 * 3600) -> dict:
|
||||
def fill_daterange(self, first: date, last: date, val: int = 24 * 3600) -> None:
|
||||
"""
|
||||
Функция заполняет диапазон дат значением val (по умолчанию val = кол-во секунд в 1 дне).
|
||||
|
||||
@ -256,9 +280,11 @@ class StatisticData:
|
||||
for day in daterange(first, last):
|
||||
self.statistic[day] = val
|
||||
|
||||
def clear_statistic(self) -> dict:
|
||||
def clear_statistic(self) -> None:
|
||||
"""
|
||||
Функция осуществляет обновление всех дней.
|
||||
Чистка статистики и установка времени по умолчанию.
|
||||
|
||||
Устанавливает время смены в 0
|
||||
"""
|
||||
self.statistic.clear()
|
||||
self.fill_daterange(self.start_date, self.end_date + timedelta(days=1), 0)
|
||||
|
467
main/tests.py
467
main/tests.py
@ -1,5 +1,5 @@
|
||||
"""
|
||||
Тесты.
|
||||
Тестирование работы программы.
|
||||
"""
|
||||
|
||||
|
||||
@ -21,14 +21,35 @@ from main.extra_func import log
|
||||
|
||||
|
||||
class UsersBaseTestCase(TestCase):
|
||||
"""Базовый класс загружения данных для тестов с пользователями"""
|
||||
"""
|
||||
Базовый класс загрузки данных для тестов с пользователями.
|
||||
|
||||
Для тестов используются фикстуры тестовых пользователей (test_users.json).
|
||||
"""
|
||||
fixtures = ['fixtures/test_users.json']
|
||||
|
||||
def setUp(self):
|
||||
"""Добавление в переменные почт и клиентов для пользователей"""
|
||||
def setUp(self) -> None:
|
||||
"""
|
||||
Функция предустановки значений переменных.
|
||||
|
||||
Добавляем email тестовых пользователей и создаем клиентов для тестов.
|
||||
|
||||
:param light_agent: email тестового пользователя с правами light_agent
|
||||
:type light_agent: :class:`str`
|
||||
:param engineer: email тестового пользователя с правами engineer
|
||||
:type engineer: :class:`str`
|
||||
:param admin: email тестового пользователя с правами admin
|
||||
:type admin: :class:`str`
|
||||
:param agent_client: клиент, залогиненный как пользователь с email light_agent
|
||||
:type agent_client: :class:`django.test.client.Client`
|
||||
:param engineer_client: клиент, залогиненный как пользователь с email engineer
|
||||
:type engineer_client: :class:`django.test.client.Client`
|
||||
:param admin_client: клиент, залогиненный как пользователь с email admin
|
||||
:type admin_client: :class:`django.test.client.Client`
|
||||
"""
|
||||
self.light_agent = '123@test.ru'
|
||||
self.admin = 'admin@gmail.com'
|
||||
self.engineer = 'customer@example.com'
|
||||
self.engineer = 'customer@example.com'
|
||||
self.agent_client = Client()
|
||||
self.agent_client.force_login(get_user_model().objects.get(email=self.light_agent))
|
||||
self.admin_client = Client()
|
||||
@ -39,13 +60,27 @@ class UsersBaseTestCase(TestCase):
|
||||
|
||||
class RegistrationTestCase(TestCase):
|
||||
"""
|
||||
Класс тестирования регистрации пользователя.
|
||||
Класс тестирования регистрации.
|
||||
|
||||
Для тестов используются фикстуры с данными пользователей engineer и light_agent (data.json).
|
||||
"""
|
||||
fixtures = ['fixtures/data.json']
|
||||
|
||||
def setUp(self) -> None:
|
||||
"""
|
||||
Функция предтестовых настроек.
|
||||
Функция предустановки значений переменных.
|
||||
|
||||
Добавляем email тестовых пользователей и создаем клиентов для тестов.
|
||||
|
||||
:param email_backend: locmem бэкенд со списком отправленных писем
|
||||
:type email_backend: :class:`str`
|
||||
:param any_zendesk_user_email: email пользователя, зарегистрированного на Zendesk
|
||||
:type any_zendesk_user_email: :class:`str`
|
||||
:param zendesk_admin_email: email администратора
|
||||
:type zendesk_admin_email: :class:`str`
|
||||
:param client: новый клиент
|
||||
:type client: :class:`django.test.client.Client`
|
||||
|
||||
"""
|
||||
self.email_backend = 'django.core.mail.backends.locmem.EmailBackend'
|
||||
self.any_zendesk_user_email = 'idar.sokurov.05@mail.ru'
|
||||
@ -54,31 +89,43 @@ class RegistrationTestCase(TestCase):
|
||||
|
||||
def test_registration_complete_redirect(self) -> None:
|
||||
"""
|
||||
Функция тестирования успешно завершенной регистрации.
|
||||
Функция тестирования успешной регистрации пользователя.
|
||||
|
||||
Проверяет, что в случае если email пользователя зарегистрирован на Zendesk, была заполнена форма регистрации
|
||||
и направлено письмо со ссылкой для завершения регистрации, происходит редирект на страницу завершения
|
||||
регистрации.
|
||||
"""
|
||||
with self.settings(EMAIL_BACKEND=self.email_backend):
|
||||
resp = self.client.post(reverse('registration'), data={'email': self.any_zendesk_user_email})
|
||||
self.assertRedirects(resp, reverse('password_reset_done'))
|
||||
|
||||
def test_registration_fail_redirect(self):
|
||||
def test_registration_fail_redirect(self) -> None:
|
||||
"""
|
||||
Функция тестирования неуспешной регистрации.
|
||||
Функция тестирования не успешной регистрации пользователя (введен email, не зарегистрированный на Zendesk).
|
||||
|
||||
Проверяет, что происходит редирект на страницу "registration disallowed"
|
||||
"""
|
||||
with self.settings(EMAIL_BACKEND=self.email_backend):
|
||||
resp = self.client.post(reverse('registration'), data={'email': self.any_zendesk_user_email + 'asd'})
|
||||
self.assertRedirects(resp, reverse('django_registration_disallowed'))
|
||||
|
||||
def test_registration_user_already_exist(self):
|
||||
def test_registration_user_already_exist(self) -> None:
|
||||
"""
|
||||
Функция тестирования попытки регистрации уже зарегистрированного пользователя.
|
||||
Функция тестирования попытки зарегистрироваться, используя email уже зарегистрированного в приложении
|
||||
пользователя ("123@test.ru").
|
||||
|
||||
Проверяет, что пользователь получает сообщение "Этот адрес электронной почты уже используется"
|
||||
"""
|
||||
with self.settings(EMAIL_BACKEND=self.email_backend) and translation.override('ru'):
|
||||
resp = self.client.post(reverse('registration'), data={'email': '123@test.ru'})
|
||||
self.assertContains(resp, 'Этот адрес электронной почты уже используется', count=1, status_code=200)
|
||||
|
||||
def test_registration_send_email(self):
|
||||
def test_registration_send_email(self) -> None:
|
||||
"""
|
||||
Функция тестирования отправки email.
|
||||
Функция тестирования отправки email пользователю при регистрации.
|
||||
|
||||
Проверяет отправку уведомления на указанный пользователем адрес, а также содержание письма (заголовка и тела)
|
||||
через email locmem backend.
|
||||
"""
|
||||
with self.settings(EMAIL_BACKEND=self.email_backend):
|
||||
response: HttpResponseRedirect = \
|
||||
@ -94,9 +141,11 @@ class RegistrationTestCase(TestCase):
|
||||
correct_body = render_to_string('registration/password_reset_email.html', email_context, response.request)
|
||||
self.assertEqual(mail.outbox[0].body, correct_body)
|
||||
|
||||
def test_registration_user_creating(self):
|
||||
def test_registration_user_creating(self) -> None:
|
||||
"""
|
||||
Функция тестирования регистрации пользователя (сверяем имя с именем в Zendesk.
|
||||
Функция тестирования создания пользователя приложения при регистрации.
|
||||
|
||||
Проверяет соответствие имени созданного пользователя с именем пользователя в Zendesk
|
||||
"""
|
||||
with self.settings(EMAIL_BACKEND=self.email_backend):
|
||||
self.client.post(reverse('registration'), data={'email': self.any_zendesk_user_email})
|
||||
@ -104,9 +153,11 @@ class RegistrationTestCase(TestCase):
|
||||
zendesk_user = zenpy.get_user(self.any_zendesk_user_email)
|
||||
self.assertEqual(user.userprofile.name, zendesk_user.name)
|
||||
|
||||
def test_permissions_applying(self):
|
||||
def test_permissions_applying(self) -> None:
|
||||
"""
|
||||
Функция тестирования проверке присвоения роли admin.
|
||||
Функция тестирования создания администратора и присвоения ему соответствующих прав.
|
||||
|
||||
Проверяет, что у созданного пользователя роль "admin" и права "has_control_access".
|
||||
"""
|
||||
with self.settings(EMAIL_BACKEND=self.email_backend):
|
||||
self.client.post(reverse('registration'), data={'email': self.zendesk_admin_email})
|
||||
@ -117,47 +168,67 @@ class RegistrationTestCase(TestCase):
|
||||
|
||||
class MakeEngineerTestCase(UsersBaseTestCase):
|
||||
"""
|
||||
Класс тестов для проверки функции назначения роли engineer.
|
||||
Класс тестирования присвоения пользователю роли engineer.
|
||||
|
||||
В тестах используется @patch('main.extra_func.zenpy') Mock для работы с API Zendesk.
|
||||
"""
|
||||
|
||||
@patch('main.extra_func.zenpy')
|
||||
def test_become_engineer_redirect(self, _zenpy_mock):
|
||||
def test_become_engineer_redirect(self, _zenpy_mock: Mock) -> None:
|
||||
"""
|
||||
Функция проверки переадресации пользователя на рабочую страницу после назначения роли engineer.
|
||||
Функция тестирования редиректа на рабочую страницу тестового пользователя при назначении его инженером.
|
||||
|
||||
:param _zenpy_mock: Mock объекта zenpy для функций, работающих с API Zendesk.
|
||||
"""
|
||||
user = get_user_model().objects.get(email=self.light_agent)
|
||||
resp = self.agent_client.post(reverse_lazy('work_become_engineer'))
|
||||
self.assertRedirects(resp, reverse('work', args=[user.id]))
|
||||
self.assertEqual(resp.status_code, 302)
|
||||
self.assertFalse(_zenpy_mock.called)
|
||||
|
||||
@patch('main.extra_func.zenpy')
|
||||
def test_light_agent_make_engineer(self, zenpy_mock):
|
||||
def test_light_agent_make_engineer(self, zenpy_mock: Mock) -> None:
|
||||
"""
|
||||
Функция проверки назначения light_agent на роль engineer.
|
||||
Функция тестирования назначения легкого агента на роль инженера.
|
||||
|
||||
Проверяет установку роли "engineer" в Zendesk.
|
||||
|
||||
:param zenpy_mock: Mock объекта zenpy для функций, работающих с API Zendesk.
|
||||
"""
|
||||
self.agent_client.post(reverse_lazy('work_become_engineer'))
|
||||
self.assertEqual(zenpy_mock.update_user.call_args[0][0].custom_role_id, sets.ZENDESK_ROLES['engineer'])
|
||||
|
||||
@patch('main.extra_func.zenpy')
|
||||
def test_admin_make_engineer(self, zenpy_mock):
|
||||
def test_admin_make_engineer(self, zenpy_mock: Mock) -> None:
|
||||
"""
|
||||
Функция проверки назначения admin на роль engineer.
|
||||
Функция тестирования назначения администратора на роль инженера.
|
||||
|
||||
Проверяет установку роли "engineer" в Zendesk.
|
||||
|
||||
:param zenpy_mock: Mock объекта zenpy для функций, работающих с API Zendesk.
|
||||
"""
|
||||
self.admin_client.post(reverse_lazy('work_become_engineer'))
|
||||
self.assertEqual(zenpy_mock.update_user.call_args[0][0].custom_role_id, sets.ZENDESK_ROLES['engineer'])
|
||||
|
||||
@patch('main.extra_func.zenpy')
|
||||
def test_engineer_make_engineer(self, zenpy_mock):
|
||||
def test_engineer_make_engineer(self, zenpy_mock: Mock) -> None:
|
||||
"""
|
||||
Функция проверки назначения engineer на роль engineer.
|
||||
Функция тестирования назначения инженера на роль инженера.
|
||||
|
||||
Проверяет установку роли "engineer" в Zendesk.
|
||||
|
||||
:param zenpy_mock: Mock объекта zenpy для функций, работающих с API Zendesk.
|
||||
"""
|
||||
self.engineer_client.post(reverse_lazy('work_become_engineer'))
|
||||
self.assertEqual(zenpy_mock.update_user.call_args[0][0].custom_role_id, sets.ZENDESK_ROLES['engineer'])
|
||||
|
||||
@patch('main.extra_func.zenpy')
|
||||
def test_control_page_make_engineer_one(self, zenpy_mock):
|
||||
def test_control_page_make_engineer_one(self, zenpy_mock: Mock) -> None:
|
||||
"""
|
||||
Функция проверки назначения администратором на роль engineer одного пользователя.
|
||||
Функция тестирования назначения администратором одного инженера на странице "Управление".
|
||||
|
||||
Проверяет обновление администратором роли пользователя с light_agent на engineer.
|
||||
|
||||
:param zenpy_mock: Mock объекта zenpy для функций, работающих с API Zendesk.
|
||||
"""
|
||||
self.admin_client.post(
|
||||
reverse_lazy('control'),
|
||||
@ -170,9 +241,13 @@ class MakeEngineerTestCase(UsersBaseTestCase):
|
||||
self.assertEqual(mock_object.custom_role_id, sets.ZENDESK_ROLES['engineer'])
|
||||
|
||||
@patch('main.extra_func.zenpy')
|
||||
def test_control_page_make_engineer_many(self, zenpy_mock):
|
||||
def test_control_page_make_engineer_many(self, zenpy_mock: Mock) -> None:
|
||||
"""
|
||||
Функция проверки назначения администратором на роль engineer нескольких пользователей.
|
||||
Функция тестирования назначения администратором нескольких инженеров на странице "Управление".
|
||||
|
||||
Проверяет обновление администратором ролей двух пользователей с light_agent на engineer.
|
||||
|
||||
:param zenpy_mock: Mock объекта zenpy для функций, работающих с API Zendesk.
|
||||
"""
|
||||
self.admin_client.post(
|
||||
reverse_lazy('control'),
|
||||
@ -192,10 +267,23 @@ class MakeEngineerTestCase(UsersBaseTestCase):
|
||||
|
||||
|
||||
class MakeLightAgentTestCase(UsersBaseTestCase):
|
||||
"""
|
||||
Класс тестирования присвоения пользователю роли light_agent.
|
||||
|
||||
В тестах используется @patch('main.extra_func.zenpy') Mock для работы API Zendesk, а также
|
||||
@patch('main.requester.TicketListRequester.get_tickets_list_for_user', side_effect=[[]]), предоставляющий пустой
|
||||
список в качестве списка тикетов пользователя.
|
||||
"""
|
||||
|
||||
@patch('main.requester.TicketListRequester.get_tickets_list_for_user', side_effect=[[]])
|
||||
@patch('main.extra_func.zenpy')
|
||||
def test_hand_over_redirect(self, _zenpy_mock, _user_tickets_mock):
|
||||
def test_hand_over_redirect(self, _zenpy_mock: Mock, _user_tickets_mock: Mock) -> None:
|
||||
"""
|
||||
Функция тестирования переадресации инженера на рабочую страницу, после сдачи прав.
|
||||
|
||||
:param _zenpy_mock: Mock объекта zenpy для функций, работающих с API Zendesk.
|
||||
:param _user_tickets_mock: Mock, заменяющий список тикетов пользователя на пустой список.
|
||||
"""
|
||||
user = get_user_model().objects.get(email=self.engineer)
|
||||
resp = self.engineer_client.post(reverse_lazy('work_hand_over'))
|
||||
self.assertRedirects(resp, reverse('work', args=[user.id]))
|
||||
@ -203,7 +291,15 @@ class MakeLightAgentTestCase(UsersBaseTestCase):
|
||||
|
||||
@patch('main.requester.TicketListRequester.get_tickets_list_for_user', side_effect=[[]])
|
||||
@patch('main.extra_func.zenpy')
|
||||
def test_engineer_make_light_agent_no_tickets(self, zenpy_mock, _user_tickets_mock):
|
||||
def test_engineer_make_light_agent_no_tickets(self, zenpy_mock: Mock, _user_tickets_mock: Mock) -> None:
|
||||
"""
|
||||
Функция тестирования назначения инженера легким агентом, в случае, когда у него в работе нет тикетов.
|
||||
|
||||
Проверяет назначение роли light_agent в Zendesk.
|
||||
|
||||
:param zenpy_mock: Mock объекта zenpy для функций, работающих с API Zendesk.
|
||||
:param _user_tickets_mock: Mock, заменяющий список тикетов пользователя на пустой список.
|
||||
"""
|
||||
self.engineer_client.post(reverse_lazy('work_hand_over'))
|
||||
self.assertEqual(zenpy_mock.update_user.call_args[0][0].custom_role_id, sets.ZENDESK_ROLES['light_agent'])
|
||||
|
||||
@ -211,7 +307,18 @@ class MakeLightAgentTestCase(UsersBaseTestCase):
|
||||
[Mock(id=1, status='solved'), Mock(id=2, status='open'), Mock(id=3, status='open')]
|
||||
])
|
||||
@patch('main.extra_func.zenpy')
|
||||
def test_engineer_make_light_agent_with_tickets(self, zenpy_mock, _user_tickets_mock):
|
||||
def test_engineer_make_light_agent_with_tickets(self, zenpy_mock: Mock, _user_tickets_mock: Mock) -> None:
|
||||
"""
|
||||
Функция тестирования назначения инженера легким агентом, в случае, когда у него в работе есть тикеты.
|
||||
|
||||
Для тестирования принимается, что в работе у инженера находится 3 тикета, один в состоянии: решен,
|
||||
два в состоянии: открыт.
|
||||
Проверяет распределение тикетов (поместить в решенные или назначить нового ответственного),
|
||||
а также назначение роли light_agent в Zendesk.
|
||||
|
||||
:param zenpy_mock: Mock объекта zenpy для функций, работающих с API Zendesk.
|
||||
:param _user_tickets_mock: Mock, заменяющий список тикетов пользователя на пустой список.
|
||||
"""
|
||||
zenpy_mock.solved_tickets_user_id = Mock()
|
||||
self.engineer_client.post(reverse_lazy('work_hand_over'))
|
||||
|
||||
@ -223,7 +330,15 @@ class MakeLightAgentTestCase(UsersBaseTestCase):
|
||||
|
||||
@patch('main.requester.TicketListRequester.get_tickets_list_for_user', side_effect=[[]])
|
||||
@patch('main.extra_func.zenpy')
|
||||
def test_admin_make_light_agent_no_tickets(self, zenpy_mock, _user_tickets_mock):
|
||||
def test_admin_make_light_agent_no_tickets(self, zenpy_mock: Mock, _user_tickets_mock: Mock) -> None:
|
||||
"""
|
||||
Функция тестирования назначения администратора на роль легкого агента.
|
||||
|
||||
Проверяет назначение роли light_agent в Zendesk.
|
||||
|
||||
:param zenpy_mock: Mock объекта zenpy для функций, работающих с API Zendesk.
|
||||
:param _user_tickets_mock: Mock, заменяющий список тикетов пользователя на пустой список.
|
||||
"""
|
||||
self.admin_client.post(reverse_lazy('work_hand_over'))
|
||||
self.assertEqual(zenpy_mock.update_user.call_args[0][0].custom_role_id, sets.ZENDESK_ROLES['light_agent'])
|
||||
|
||||
@ -231,7 +346,18 @@ class MakeLightAgentTestCase(UsersBaseTestCase):
|
||||
[Mock(id=1, status='solved'), Mock(id=2, status='open'), Mock(id=3, status='open')]
|
||||
])
|
||||
@patch('main.extra_func.zenpy')
|
||||
def test_admin_make_light_agent_with_tickets(self, zenpy_mock, _user_tickets_mock):
|
||||
def test_admin_make_light_agent_with_tickets(self, zenpy_mock: zenpy, _user_tickets_mock: list) -> None:
|
||||
"""
|
||||
Функция тестирования назначения администратора легким агентом, в случае, когда у него в работе есть тикеты.
|
||||
|
||||
Для тестирования принимается, что в работе находится 3 тикета, один в состоянии: решен,
|
||||
два в состоянии: открыт.
|
||||
Проверяет распределение тикетов (поместить в решенные или назначить нового ответственного),
|
||||
а также назначение роли light_agent в Zendesk.
|
||||
|
||||
:param zenpy_mock: Mock объекта zenpy для функций, работающих с API Zendesk.
|
||||
:param _user_tickets_mock: Mock, заменяющий список тикетов пользователя на пустой список.
|
||||
"""
|
||||
zenpy_mock.solved_tickets_user_id = Mock()
|
||||
self.admin_client.post(reverse_lazy('work_hand_over'))
|
||||
|
||||
@ -243,19 +369,33 @@ class MakeLightAgentTestCase(UsersBaseTestCase):
|
||||
|
||||
@patch('main.requester.TicketListRequester.get_tickets_list_for_user', side_effect=[[]])
|
||||
@patch('main.extra_func.zenpy')
|
||||
def test_light_agent_make_light_agent(self, zenpy_mock, _user_tickets_mock):
|
||||
def test_light_agent_make_light_agent(self, zenpy_mock: Mock, _user_tickets_mock: Mock) -> None:
|
||||
"""
|
||||
Функция тестирования назначения легкого агента на роль легкого агента.
|
||||
|
||||
Проверяет назначение роли light_agent в Zendesk.
|
||||
|
||||
:param zenpy_mock: Mock объекта zenpy для функций, работающих с API Zendesk.
|
||||
:param _user_tickets_mock: Mock, заменяющий список тикетов пользователя на пустой список.
|
||||
"""
|
||||
self.agent_client.post(reverse_lazy('work_hand_over'))
|
||||
self.assertEqual(zenpy_mock.update_user.call_args[0][0].custom_role_id, sets.ZENDESK_ROLES['light_agent'])
|
||||
|
||||
@patch('main.requester.TicketListRequester.get_tickets_list_for_user', side_effect=[[]])
|
||||
@patch('main.extra_func.zenpy')
|
||||
def test_control_page_make_light_agent_one(self, zenpy_mock, _user_tickets_mock):
|
||||
def test_control_page_make_light_agent_one(self, zenpy_mock: Mock, _user_tickets_mock: Mock) -> None:
|
||||
"""
|
||||
Функция тестирования назначения администратором одного легкого агента на странице "Управление".
|
||||
|
||||
Проверяет обновление администратором роли пользователя с engineer на light_agent.
|
||||
|
||||
:param zenpy_mock: Mock объекта zenpy для функций, работающих с API Zendesk.
|
||||
:param _user_tickets_mock: Mock, заменяющий список тикетов пользователя на пустой список.
|
||||
"""
|
||||
self.admin_client.post(
|
||||
reverse_lazy('control'),
|
||||
data={
|
||||
'users': [get_user_model().objects.get(email=self.engineer).userprofile.id],
|
||||
'light_agent': 'light_agent'
|
||||
}
|
||||
data={'users': [get_user_model().objects.get(email=self.engineer).userprofile.id],
|
||||
'light_agent': 'light_agent'}
|
||||
)
|
||||
call_list = zenpy_mock.update_user.call_args_list
|
||||
mock_object = call_list[0][0][0]
|
||||
@ -264,7 +404,16 @@ class MakeLightAgentTestCase(UsersBaseTestCase):
|
||||
|
||||
@patch('main.requester.TicketListRequester.get_tickets_list_for_user', side_effect=[[], []])
|
||||
@patch('main.extra_func.zenpy')
|
||||
def test_control_page_make_light_agent_many(self, zenpy_mock, _user_tickets_mock):
|
||||
def test_control_page_make_light_agent_many(self, zenpy_mock: Mock, _user_tickets_mock: Mock) -> None:
|
||||
"""
|
||||
Функция тестирования назначения администратором нескольких легких агентов на странице "Управление".
|
||||
|
||||
Проверяет обновление администратором ролей двух пользователей с engineer на light_agent.
|
||||
|
||||
:param zenpy_mock: Mock объекта zenpy для функций, работающих с API Zendesk.
|
||||
:param _user_tickets_mock: Mock, заменяющий список тикетов пользователя на пустой список.
|
||||
"""
|
||||
|
||||
self.admin_client.post(
|
||||
reverse_lazy('control'),
|
||||
data={
|
||||
@ -284,27 +433,30 @@ class MakeLightAgentTestCase(UsersBaseTestCase):
|
||||
|
||||
class PasswordResetTestCase(UsersBaseTestCase):
|
||||
"""
|
||||
Класс тестов сброса пароля.
|
||||
Класс тестирования сброса пароля.
|
||||
"""
|
||||
|
||||
def setUp(self):
|
||||
"""
|
||||
Предустановленные значения для проведения тестов.
|
||||
"""
|
||||
super().setUp()
|
||||
self.email_backend = 'django.core.mail.backends.locmem.EmailBackend'
|
||||
|
||||
def test_redirect(self):
|
||||
def test_redirect(self) -> None:
|
||||
"""
|
||||
Функция проверки переадресации на страницу уведомления о сбросе пароля на email.
|
||||
Функция тестирования успешной смены пароля.
|
||||
|
||||
Проверяется переадресация на страницу завершения смены пароля, в случае, когда пользователь существует и на его
|
||||
email было направлено письмо для сброса пароля.
|
||||
"""
|
||||
with self.settings(EMAIL_BACKEND=self.email_backend):
|
||||
resp = self.agent_client.post(reverse_lazy('password_reset'), data={'email': self.light_agent})
|
||||
self.assertRedirects(resp, reverse('password_reset_done'))
|
||||
self.assertEqual(resp.status_code, 302)
|
||||
|
||||
def test_send_email(self):
|
||||
def test_send_email(self) -> None:
|
||||
"""
|
||||
Функция проверки содержания и отправки письма для установки пароля.
|
||||
Функция тестирования отправки email для сброса пароля.
|
||||
|
||||
Проверяет наличие отправленного письма, и его содержание, сверяет email адресата с email пользователя.
|
||||
"""
|
||||
with self.settings(EMAIL_BACKEND=self.email_backend):
|
||||
response: HttpResponseRedirect = \
|
||||
@ -320,25 +472,25 @@ class PasswordResetTestCase(UsersBaseTestCase):
|
||||
correct_body = render_to_string('registration/password_reset_email.html', email_context, response.request)
|
||||
self.assertEqual(mail.outbox[0].body, correct_body)
|
||||
|
||||
def test_email_invalid(self):
|
||||
def test_email_invalid(self) -> None:
|
||||
"""
|
||||
Функция проверки уведомления клиента о некорректности введенного email.
|
||||
Функция тестирования попытки смены пароля с некорректным email.
|
||||
|
||||
Проверяет уведомление пользователя о неверном адресе электронной почты.
|
||||
"""
|
||||
with self.settings(EMAIL_BACKEND=self.email_backend) and translation.override('ru'):
|
||||
resp = self.agent_client.post(reverse_lazy('password_reset'), data={'email': 1})
|
||||
self.assertContains(resp, 'Введите правильный адрес электронной почты.', count=1, status_code=200)
|
||||
|
||||
def test_user_does_not_exist(self):
|
||||
def test_user_does_not_exist(self) -> None:
|
||||
"""
|
||||
Функция корректности отработки неверно введенного email.
|
||||
Функция тестирования попытки смены пароля с email, который не зарегистрирован.
|
||||
|
||||
Проверяет отсутствие отправки письма о смене пароля.
|
||||
"""
|
||||
with self.settings(EMAIL_BACKEND=self.email_backend):
|
||||
resp = self.agent_client.post(
|
||||
reverse_lazy('password_reset'),
|
||||
data={
|
||||
'email': self.light_agent + str(random.random())
|
||||
}
|
||||
)
|
||||
resp = self.agent_client.post(reverse_lazy('password_reset'),
|
||||
data={'email': self.light_agent + str(random.random())})
|
||||
self.assertRedirects(resp, reverse('password_reset_done'))
|
||||
self.assertEqual(resp.status_code, 302)
|
||||
self.assertEqual(len(mail.outbox), 0)
|
||||
@ -348,25 +500,27 @@ class PasswordChangeTestCase(UsersBaseTestCase):
|
||||
"""
|
||||
Класс тестирования смены пароля.
|
||||
"""
|
||||
def setUp(self):
|
||||
"""
|
||||
Предустановленные значения для проведения тестов.
|
||||
"""
|
||||
|
||||
def setUp(self) -> None:
|
||||
super().setUp()
|
||||
self.set_password()
|
||||
|
||||
def set_password(self):
|
||||
def set_password(self) -> None:
|
||||
"""
|
||||
Пароль, сформированный для тестирования.
|
||||
Функция предустанавливает тестовому пользователю с ролью light_agent пароль 'ImpossiblyHardPassword' и создает
|
||||
клиента с соответствующими данным для тестирования.
|
||||
"""
|
||||
user: get_user_model() = get_user_model().objects.get(email=self.light_agent)
|
||||
user = get_user_model().objects.get(email=self.light_agent)
|
||||
user.set_password('ImpossiblyHardPassword')
|
||||
user.save()
|
||||
self.agent_client.force_login(get_user_model().objects.get(email=self.light_agent))
|
||||
|
||||
def test_change_successful(self):
|
||||
def test_change_successful(self) -> None:
|
||||
"""
|
||||
Функция тестирования успешного изменения пароля.
|
||||
Функция тестирования успешной смены пароля.
|
||||
|
||||
Проверяет установку нового пароля пользователю при вводе корректных данных: старый пароль, новый пароль
|
||||
(2 раза).
|
||||
"""
|
||||
self.agent_client.post(
|
||||
reverse_lazy('password_change'),
|
||||
@ -379,9 +533,11 @@ class PasswordChangeTestCase(UsersBaseTestCase):
|
||||
user = get_user_model().objects.get(email=self.light_agent)
|
||||
self.assertTrue(user.check_password('EasyPassword'))
|
||||
|
||||
def test_invalid_old_password(self):
|
||||
def test_invalid_old_password(self) -> None:
|
||||
"""
|
||||
Функция тестирования отработки неверно введенного старого пароля при смене.
|
||||
Функция тестирования смены пароля, при неверном вводе старого пароля.
|
||||
|
||||
Проверяет текст уведомления пользователя 'Ваш старый пароль введен неправильно'.
|
||||
"""
|
||||
with translation.override('ru'):
|
||||
resp = self.agent_client.post(
|
||||
@ -394,9 +550,11 @@ class PasswordChangeTestCase(UsersBaseTestCase):
|
||||
)
|
||||
self.assertContains(resp, 'Ваш старый пароль введен неправильно', count=1, status_code=200)
|
||||
|
||||
def test_different_new_passwords(self):
|
||||
def test_different_new_passwords(self) -> None:
|
||||
"""
|
||||
Функция тестирования случая с вводом двух разных новых паролей.
|
||||
Функция тестирования смены пароля, при вводе не совпадающих новых паролей.
|
||||
|
||||
Проверяет текст уведомления пользователя 'Введенные пароли не совпадают'.
|
||||
"""
|
||||
with translation.override('ru'):
|
||||
resp = self.agent_client.post(
|
||||
@ -411,7 +569,9 @@ class PasswordChangeTestCase(UsersBaseTestCase):
|
||||
|
||||
def test_invalid_new_password1(self):
|
||||
"""
|
||||
Функция тестирования случая с неправильно подобранным новым паролем (слишком короткий).
|
||||
Функция тестирования попытки смены пароля, когда новый пароль не соответствует требованиям: слишком короткий.
|
||||
|
||||
Проверяет текст уведомления пользователя 'Введённый пароль слишком короткий'.
|
||||
"""
|
||||
with translation.override('ru'):
|
||||
resp = self.agent_client.post(
|
||||
@ -424,9 +584,12 @@ class PasswordChangeTestCase(UsersBaseTestCase):
|
||||
)
|
||||
self.assertContains(resp, 'Введённый пароль слишком короткий', count=1, status_code=200)
|
||||
|
||||
def test_invalid_new_password2(self):
|
||||
def test_invalid_new_password2(self) -> None:
|
||||
"""
|
||||
Функция тестирования случая с неправильно подобранным новым паролем (употребляются только цифры).
|
||||
Функция тестирования попытки смены пароля, когда новый пароль не соответствует требованиям: состоит
|
||||
только из цифр.
|
||||
|
||||
Проверяет текст уведомления пользователя 'Введённый пароль состоит только из цифр'.
|
||||
"""
|
||||
with translation.override('ru'):
|
||||
resp = self.agent_client.post(
|
||||
@ -441,7 +604,10 @@ class PasswordChangeTestCase(UsersBaseTestCase):
|
||||
|
||||
def test_invalid_new_password3(self):
|
||||
"""
|
||||
Функция тестирования случая с неправильно подобранным новым паролем (совпадает с именем пользователя).
|
||||
Функция тестирования попытки смены пароля, когда новый пароль не соответствует требованиям: аналогичен имени
|
||||
пользователя.
|
||||
|
||||
Проверяет текст уведомления пользователя 'Введённый пароль слишком похож на имя пользователя'.
|
||||
"""
|
||||
with translation.override('ru'):
|
||||
resp = self.agent_client.post(
|
||||
@ -458,26 +624,40 @@ class PasswordChangeTestCase(UsersBaseTestCase):
|
||||
class GetTicketsTestCase(UsersBaseTestCase):
|
||||
"""
|
||||
Класс тестов для проверки функции получения тикетов.
|
||||
|
||||
В тестах используются @patch('main.views.zenpy.get_user') и @patch('main.views.zenpy.get_user')
|
||||
для работы с API Zendesk.
|
||||
"""
|
||||
|
||||
@patch('main.views.zenpy.get_user')
|
||||
@patch('main.extra_func.zenpy')
|
||||
def test_redirect(self, _zenpy_mock, get_user_mock):
|
||||
def test_redirect(self, _zenpy_mock: Mock, get_user_mock: Mock) -> None:
|
||||
"""
|
||||
Функция проверки переадресации пользователя на рабочую страницу.
|
||||
|
||||
Проверяет редирект на рабочую страницу, в случае, когда пользователь с правами инженера заполняет форму
|
||||
принятия тикетов в работу.
|
||||
|
||||
:param _zenpy_mock: Mock объекта zenpy для функций, работающих с API Zendesk.
|
||||
:param get_user_mock: Mock объекта zenpy_user.
|
||||
"""
|
||||
get_user_mock.return_value = Mock()
|
||||
user = get_user_model().objects.get(email=self.engineer)
|
||||
resp = self.engineer_client.post(reverse('work_get_tickets'))
|
||||
self.assertRedirects(resp, reverse('work', args=[user.id]))
|
||||
self.assertEqual(resp.status_code, 302)
|
||||
self.assertFalse(_zenpy_mock.called)
|
||||
|
||||
@patch('main.views.zenpy')
|
||||
@patch('main.views.get_tickets_list_for_group')
|
||||
def test_take_one_ticket(self, group_tickets_mock, zenpy_mock):
|
||||
def test_take_one_ticket(self, group_tickets_mock: Mock, zenpy_mock: Mock) -> None:
|
||||
"""
|
||||
Функция проверки назначения одного тикета на engineer.
|
||||
|
||||
Проверяет соответствие ответственного за тикет объекта tickets и тестового клиента правами инженера,
|
||||
направившего запрос на назначение одного тикета.
|
||||
|
||||
:param zenpy_mock: Mock объекта zenpy для функций, работающих с API Zendesk.
|
||||
:param group_tickets_mock: Mock списка не назначенных и нерешенных тикетов группы.
|
||||
"""
|
||||
group_tickets_mock.return_value = [Mock()]
|
||||
zenpy_mock.get_user.return_value = Mock(role='agent', custom_role_id=sets.ZENDESK_ROLES['engineer'])
|
||||
@ -487,9 +667,15 @@ class GetTicketsTestCase(UsersBaseTestCase):
|
||||
|
||||
@patch('main.views.get_tickets_list_for_group')
|
||||
@patch('main.views.zenpy')
|
||||
def test_take_many_tickets(self, zenpy_mock, group_tickets_mock):
|
||||
def test_take_many_tickets(self, zenpy_mock: Mock, group_tickets_mock: Mock) -> None:
|
||||
"""
|
||||
Функция проверки назначения нескольких тикетов на engineer.
|
||||
|
||||
Проверяет соответствие ответственного за тикеты объекта tickets и тестового клиента правами инженера,
|
||||
направившего запрос на назначение трех тикетов.
|
||||
|
||||
:param zenpy_mock: Mock объекта zenpy для функций, работающих с API Zendesk.
|
||||
:param group_tickets_mock: Mock списка не назначенных и нерешенных тикетов группы.
|
||||
"""
|
||||
group_tickets_mock.return_value = [Mock()] * 3
|
||||
zenpy_mock.get_user.return_value = Mock(role='agent', custom_role_id=sets.ZENDESK_ROLES['engineer'])
|
||||
@ -500,9 +686,12 @@ class GetTicketsTestCase(UsersBaseTestCase):
|
||||
|
||||
@patch('main.views.zenpy.get_user')
|
||||
@patch('main.views.zenpy')
|
||||
def test_light_agent_take_ticket(self, zenpy_mock, get_user_mock):
|
||||
def test_light_agent_take_ticket(self, zenpy_mock: Mock, get_user_mock: Mock) -> None:
|
||||
"""
|
||||
Функция проверки попытки назначения тикета на light_agent.
|
||||
|
||||
:param zenpy_mock: Mock объекта zenpy для функций, работающих с API Zendesk.
|
||||
:param get_user_mock: Mock объекта zenpy_user.
|
||||
"""
|
||||
get_user_mock.return_value = Mock(role='agent', custom_role_id=sets.ZENDESK_ROLES['light_agent'])
|
||||
self.agent_client.post(reverse('work_get_tickets'), data={'count_tickets': 3})
|
||||
@ -511,9 +700,14 @@ class GetTicketsTestCase(UsersBaseTestCase):
|
||||
|
||||
@patch('main.views.zenpy')
|
||||
@patch('main.views.get_tickets_list_for_group')
|
||||
def test_take_zero_tickets(self, tickets_mock, zenpy_mock):
|
||||
def test_take_zero_tickets(self, tickets_mock: Mock, zenpy_mock: Mock) -> None:
|
||||
"""
|
||||
Функция проверки попытки назначения нуля тикета на engineer.
|
||||
Функция проверки попытки назначения нулевого количества тикетов.
|
||||
|
||||
Проверяет, что список тикетов остался пустым.
|
||||
|
||||
:param zenpy_mock: Mock объекта zenpy для функций, работающих с API Zendesk.
|
||||
:param tickets_mock: Mock списка тикетов - возвращает пустой список.
|
||||
"""
|
||||
tickets_mock.return_value = [Mock()] * 3
|
||||
zenpy_mock.get_user.return_value = Mock(role='agent', custom_role_id=sets.ZENDESK_ROLES['engineer'])
|
||||
@ -523,9 +717,15 @@ class GetTicketsTestCase(UsersBaseTestCase):
|
||||
|
||||
@patch('main.views.get_tickets_list_for_group')
|
||||
@patch('main.views.zenpy')
|
||||
def test_take_invalid_count_tickets(self, zenpy_mock, group_tickets_mock):
|
||||
def test_take_invalid_count_tickets(self, zenpy_mock: Mock, group_tickets_mock: Mock) -> None:
|
||||
"""
|
||||
Функция проверки попытки назначения нуля тикетов на engineer.
|
||||
Функция проверки попытки назначения некорректного количества тикетов (введении в форму назначения тикетов
|
||||
не числового значения, а строки).
|
||||
|
||||
Проверяет, отсутствие списка тикетов.
|
||||
|
||||
:param zenpy_mock: Mock объекта zenpy для функций, работающих с API Zendesk.
|
||||
:param group_tickets_mock: Mock списка не назначенных и нерешенных тикетов группы.
|
||||
"""
|
||||
group_tickets_mock.return_value = [Mock()] * 3
|
||||
zenpy_mock.get_user.return_value = Mock(role='agent', custom_role_id=sets.ZENDESK_ROLES['engineer'])
|
||||
@ -537,12 +737,25 @@ class GetTicketsTestCase(UsersBaseTestCase):
|
||||
class ProfileTestCase(TestCase):
|
||||
"""
|
||||
Класс тестов для проверки синхронизации профиля пользователя.
|
||||
|
||||
Для тестов используются фикстуры тестовых пользователей (profile.json).
|
||||
"""
|
||||
fixtures = ['fixtures/profile.json']
|
||||
|
||||
def setUp(self):
|
||||
def setUp(self) -> None:
|
||||
"""
|
||||
Предустановленные значения для проведения тестов.
|
||||
Функция предустановки значений переменных.
|
||||
|
||||
Добавляем email тестовых пользователей Zendesk и создаем клиентов для тестов.
|
||||
|
||||
:param zendesk_agent_email: email тестового пользователя с правами light_agent
|
||||
:type zendesk_agent_email: :class:`str`
|
||||
:param zendesk_admin_email: email тестового пользователя с правами admin
|
||||
:type zendesk_admin_email: :class:`str`
|
||||
:param client: клиент, залогиненный как пользователь с email zendesk_agent_email
|
||||
:type client: :class:`django.test.client.Client`
|
||||
:param admin_client: клиент, залогиненный как пользователь с zendesk_admin_email
|
||||
:type admin_client: :class:`django.test.client.Client`
|
||||
"""
|
||||
self.zendesk_agent_email = 'krav-88@mail.ru'
|
||||
self.zendesk_admin_email = 'idar.sokurov.05@mail.ru'
|
||||
@ -551,32 +764,42 @@ class ProfileTestCase(TestCase):
|
||||
self.admin_client = Client()
|
||||
self.admin_client.force_login(get_user_model().objects.get(email=self.zendesk_admin_email))
|
||||
|
||||
def test_correct_username(self):
|
||||
def test_correct_username(self) -> None:
|
||||
"""
|
||||
Функция проверки синхронизации имени пользователя.
|
||||
|
||||
Проверяет соответствие имени пользователя из контекста страницы профиля имени пользователя в Zendesk.
|
||||
"""
|
||||
resp = self.client.get(reverse('profile'))
|
||||
self.assertEqual(resp.context['profile'].name, zenpy.get_user(self.zendesk_agent_email).name)
|
||||
|
||||
def test_correct_email(self):
|
||||
def test_correct_email(self) -> None:
|
||||
"""
|
||||
Функция проверки синхронизации почты пользователя.
|
||||
|
||||
Проверяет соответствие email пользователя из контекста страницы профиля email пользователя в Zendesk.
|
||||
"""
|
||||
resp = self.client.get(reverse('profile'))
|
||||
self.assertEqual(resp.context['profile'].user.email, zenpy.get_user(self.zendesk_agent_email).email)
|
||||
|
||||
def test_correct_role(self):
|
||||
def test_correct_role(self) -> None:
|
||||
"""
|
||||
Функция проверки синхронизации роли пользователя.
|
||||
|
||||
Проверяет соответствие роли пользователя из контекста страницы профиля роли пользователя в Zendesk. Проверка
|
||||
осуществляется на примере администратора и агента.
|
||||
"""
|
||||
resp = self.client.get(reverse('profile'))
|
||||
self.assertEqual(resp.context['profile'].role, zenpy.get_user(self.zendesk_agent_email).role)
|
||||
resp = self.admin_client.get(reverse('profile'))
|
||||
self.assertEqual(resp.context['profile'].role, zenpy.get_user(self.zendesk_admin_email).role)
|
||||
|
||||
def test_correct_custom_role_id(self):
|
||||
def test_correct_custom_role_id(self) -> None:
|
||||
"""
|
||||
Функция проверки синхронизации рабочей роли пользователя.
|
||||
|
||||
Проверяет соответствие id рабочей роли пользователя из контекста страницы профиля id
|
||||
роли пользователя в Zendesk. Проверка осуществляется на примере администратора и агента.
|
||||
"""
|
||||
resp = self.client.get(reverse('profile'))
|
||||
user = zenpy.get_user(self.zendesk_agent_email)
|
||||
@ -585,9 +808,11 @@ class ProfileTestCase(TestCase):
|
||||
user = zenpy.get_user(self.zendesk_admin_email)
|
||||
self.assertEqual(resp.context['profile'].custom_role_id, user.custom_role_id if user.custom_role_id else 0)
|
||||
|
||||
def test_correct_image(self):
|
||||
def test_correct_image(self) -> None:
|
||||
"""
|
||||
Функция проверки синхронизации изображения пользователя.
|
||||
|
||||
Проверяет соответствие аватарки пользователя из контекста страницы профиля аватарке пользователя в Zendesk.
|
||||
"""
|
||||
resp = self.client.get(reverse('profile'))
|
||||
user = zenpy.get_user(self.zendesk_agent_email)
|
||||
@ -595,38 +820,78 @@ class ProfileTestCase(TestCase):
|
||||
|
||||
|
||||
class LoggingTestCase(UsersBaseTestCase):
|
||||
"""
|
||||
Класс тестирования процесса логгирования.
|
||||
"""
|
||||
|
||||
def setUp(self):
|
||||
def setUp(self) -> None:
|
||||
"""
|
||||
Функция предустановки значений переменных.
|
||||
|
||||
Определяем профили пользователей с разными ролями.
|
||||
|
||||
:param admin_profile: профиль тестового пользователя с правами admin
|
||||
:type admin_profile: :class:`Userprofile`
|
||||
:param agent_profile: профиль тестового пользователя с правами light_agent
|
||||
:type agent_profile: :class:`Userprofile`
|
||||
:param engineer_profile: профиль тестового пользователя с правами engineer
|
||||
:type engineer_profile: :class:`Userprofile`
|
||||
"""
|
||||
super().setUp()
|
||||
self.admin_profile = get_user_model().objects.get(email=self.admin).userprofile
|
||||
self.agent_profile = get_user_model().objects.get(email=self.light_agent).userprofile
|
||||
self.engineer_profile = get_user_model().objects.get(email=self.engineer).userprofile
|
||||
|
||||
@staticmethod
|
||||
def get_file_output():
|
||||
def get_file_output() -> str:
|
||||
"""
|
||||
Получение данных из файла логов.
|
||||
"""
|
||||
with open('logs/logs.csv', 'r') as file:
|
||||
file_output = file.readlines()[-1]
|
||||
return file_output
|
||||
|
||||
def test_engineer_with_admin(self):
|
||||
def test_engineer_with_admin(self) -> None:
|
||||
"""
|
||||
Функция проверки корректной записи лога по смене роли инженера в файл.
|
||||
|
||||
Сравнивает запись в файле и созданный лог с переданными значениями профилей инженера и администратора
|
||||
для смены прав.
|
||||
"""
|
||||
log(self.engineer_profile, self.admin_profile)
|
||||
file_output = self.get_file_output()
|
||||
self.assertEqual(file_output, f'UserForAccessTest,engineer,'
|
||||
f'{str(timezone.now().today())[:16]},ZendeskAdmin\n')
|
||||
|
||||
def test_engineer_without_admin(self):
|
||||
def test_engineer_without_admin(self) -> None:
|
||||
"""
|
||||
Функция проверки корректной записи лога по смене роли инженера в файл без указания администратора.
|
||||
|
||||
Сравнивает запись в файле и созданный лог с переданным значением профиля инженера для смены прав.
|
||||
"""
|
||||
log(self.engineer_profile)
|
||||
file_output = self.get_file_output()
|
||||
self.assertEqual(file_output, f'UserForAccessTest,engineer,'
|
||||
f'{str(timezone.now().today())[:16]},UserForAccessTest\n')
|
||||
|
||||
def test_light_agent_with_admin(self):
|
||||
def test_light_agent_with_admin(self) -> None:
|
||||
"""
|
||||
Функция проверки корректной записи лога по смене роли агента в файл.
|
||||
|
||||
Сравнивает запись в файле и созданный лог с переданными значениями профилей агента и администратора
|
||||
для смены прав.
|
||||
"""
|
||||
log(self.agent_profile, self.admin_profile)
|
||||
file_output = self.get_file_output()
|
||||
self.assertEqual(file_output, f'UserForAccessTest,light_agent,'
|
||||
f'{str(timezone.now().today())[:16]},ZendeskAdmin\n')
|
||||
|
||||
def test_light_agent_without_admin(self):
|
||||
def test_light_agent_without_admin(self) -> None:
|
||||
"""
|
||||
Функция проверки корректной записи лога по смене роли агента в файл без указания администратора.
|
||||
|
||||
Сравнивает запись в файле и созданный лог с переданным значением профиля агента для смены прав.
|
||||
"""
|
||||
log(self.agent_profile)
|
||||
file_output = self.get_file_output()
|
||||
self.assertEqual(file_output, f'UserForAccessTest,light_agent,'
|
||||
|
@ -61,7 +61,7 @@ def setup_context(**kwargs) -> Dict[str, Any]:
|
||||
|
||||
class CustomRegistrationView(RegistrationView):
|
||||
"""
|
||||
Отображение и логика работы страницы регистрации пользователя.
|
||||
Класс отображения и логики работы страницы регистрации пользователя.
|
||||
|
||||
:param form_class: Форма, которую необходимо заполнить для регистрации
|
||||
:type form_class: :class:`forms.CustomRegistrationForm`
|
||||
@ -86,9 +86,12 @@ class CustomRegistrationView(RegistrationView):
|
||||
def register(self, form: CustomRegistrationForm) -> Optional[get_user_model()]:
|
||||
"""
|
||||
Функция регистрации пользователя.
|
||||
1. Ввод email пользователя, указанный на Zendesk
|
||||
|
||||
1. Ввод email пользователя, указанный на Zendesk.
|
||||
|
||||
2. В случае если пользователь с данным паролем зарегистрирован на Zendesk и относится к организации SYSTEM,
|
||||
происходит сброс ссылки с установлением пароля на указанный email
|
||||
происходит сброс ссылки с установлением пароля на указанный email.
|
||||
|
||||
3. Создается пользователь class User, а также его профиль.
|
||||
|
||||
:param form: Email пользователя на Zendesk
|
||||
@ -133,7 +136,7 @@ class CustomRegistrationView(RegistrationView):
|
||||
"""
|
||||
Функция дает разрешение на просмотр страница администратора, если пользователь имеет роль admin.
|
||||
|
||||
:param user: авторизованный пользователь (получает разрешение, имея роль "admin")
|
||||
:param user: Авторизованный пользователь (получает разрешение, имея роль "admin")
|
||||
"""
|
||||
if user.userprofile.role == 'admin':
|
||||
content_type = ContentType.objects.get_for_model(UserProfile)
|
||||
@ -148,8 +151,8 @@ class CustomRegistrationView(RegistrationView):
|
||||
Функция возвращает url-адрес страницы, куда нужно перейти после успешной/не успешной регистрации.
|
||||
Используется самой django-registration.
|
||||
|
||||
:param user: пользователь, пытающийся зарегистрироваться
|
||||
:return: адресация на страницу успешной регистрации
|
||||
:param user: Пользователь, пытающийся зарегистрироваться
|
||||
:return: Адресация на страницу успешной регистрации
|
||||
"""
|
||||
return self.urls[self.redirect_url]
|
||||
|
||||
@ -158,8 +161,8 @@ def registration_error(request: WSGIRequest) -> HttpResponse:
|
||||
"""
|
||||
Функция отображения страницы ошибки регистрации.
|
||||
|
||||
:param request: регистрация
|
||||
:return: адресация на страницу ошибки
|
||||
:param request: Регистрация
|
||||
:return: Адресация на страницу ошибки
|
||||
"""
|
||||
return render(request, 'django_registration/registration_error.html')
|
||||
|
||||
@ -169,8 +172,8 @@ def profile_page(request: WSGIRequest) -> HttpResponse:
|
||||
"""
|
||||
Функция отображения страницы профиля.
|
||||
|
||||
:param request: данные пользователя из БД
|
||||
:return: адресация на страницу пользователя
|
||||
:param request: Данные пользователя из БД
|
||||
:return: Адресация на страницу пользователя
|
||||
"""
|
||||
user_profile: UserProfile = request.user.userprofile
|
||||
update_profile(user_profile)
|
||||
@ -187,9 +190,9 @@ def work_page(request: WSGIRequest, required_id: int) -> HttpResponse:
|
||||
"""
|
||||
Функция отображения страницы "Управления правами" для текущего пользователя (login_required).
|
||||
|
||||
:param request: объект пользователя
|
||||
:param request: Объект пользователя
|
||||
:param id: id пользователя, используется для динамической адресации
|
||||
:return: адресация на страницу "Управления правами" (либо на страницу "Авторизации", если id и user.id не совпадают
|
||||
:return: Адресация на страницу "Управления правами" (либо на страницу "Авторизации", если id и user.id не совпадают
|
||||
"""
|
||||
users = get_users_list()
|
||||
if request.user.id == required_id:
|
||||
@ -227,8 +230,8 @@ def work_hand_over(request: WSGIRequest) -> HttpResponseRedirect:
|
||||
"""
|
||||
Функция позволяет текущему пользователю сдать права, а именно сменить в Zendesk роль с "engineer" на "light_agent"
|
||||
|
||||
:param request: данные текущего пользователя (login_required)
|
||||
:return: перезагрузка текущей страницы после выполнения смены роли
|
||||
:param request: Данные текущего пользователя (login_required)
|
||||
:return: Перезагрузка текущей страницы после выполнения смены роли
|
||||
"""
|
||||
make_light_agent(request.user.userprofile, request.user)
|
||||
return set_session_params_for_work_page(request)
|
||||
@ -240,8 +243,8 @@ def work_become_engineer(request: WSGIRequest) -> HttpResponseRedirect:
|
||||
Функция позволяет текущему пользователю получить права, а именно сменить в Zendesk роль с "light_agent"
|
||||
на "engineer".
|
||||
|
||||
:param request: данные текущего пользователя (login_required)
|
||||
:return: перезагрузка текущей страницы после выполнения смены роли
|
||||
:param request: Данные текущего пользователя (login_required)
|
||||
:return: Перезагрузка текущей страницы после выполнения смены роли
|
||||
"""
|
||||
make_engineer(request.user.userprofile, request.user)
|
||||
return set_session_params_for_work_page(request)
|
||||
@ -250,9 +253,10 @@ def work_become_engineer(request: WSGIRequest) -> HttpResponseRedirect:
|
||||
@login_required()
|
||||
def work_get_tickets(request: WSGIRequest) -> HttpResponse:
|
||||
"""
|
||||
Функция получения тикетов в работу.
|
||||
|
||||
:param request:
|
||||
:return:
|
||||
:param request: Запрос на принятие тикетов в работу
|
||||
:return: Перезагрузка рабочей страницы
|
||||
"""
|
||||
zenpy_user = zenpy.get_user(request.user.email)
|
||||
|
||||
@ -289,6 +293,8 @@ class AdminPageView(LoginRequiredMixin, PermissionRequiredMixin, SuccessMessageM
|
||||
:type form_class: :class:`forms.AdminPageUsersForm`
|
||||
:param success_url: Адрес страницы администратора
|
||||
:type success_url: :class:`HttpResponseRedirect`
|
||||
:param success_message: Уведомление об изменении прав
|
||||
:type success_url: :class:`str`
|
||||
"""
|
||||
permission_required = 'main.has_control_access'
|
||||
template_name = 'pages/adm_ruleset.html'
|
||||
@ -333,7 +339,12 @@ class AdminPageView(LoginRequiredMixin, PermissionRequiredMixin, SuccessMessageM
|
||||
|
||||
class CustomLoginView(LoginView):
|
||||
"""
|
||||
Отображение страницы авторизации пользователя
|
||||
Класс отображения страницы авторизации пользователя.
|
||||
|
||||
:param extra_context: Добавление в контекст статус пользователя "залогинен"
|
||||
:type extra_context: :class:`dict`
|
||||
:param form_class: Форма страницы авторизации
|
||||
:type form_class: :class: forms.CustomAuthenticationForm
|
||||
"""
|
||||
extra_context = setup_context(login_lit=True)
|
||||
form_class = CustomAuthenticationForm
|
||||
@ -353,7 +364,8 @@ class UsersViewSet(viewsets.ReadOnlyModelViewSet):
|
||||
|
||||
def list(self, request: WSGIRequest, *args, **kwargs) -> Response:
|
||||
"""
|
||||
Функция возвращает список пользователей, список пользователей Zendesk, количество engineers и light-agents.
|
||||
Функция возвращает список пользователей Zendesk, количество engineers и light-agents.
|
||||
|
||||
:param request: Запрос
|
||||
:param args: Аргументы
|
||||
:param kwargs: Параметры
|
||||
@ -376,6 +388,7 @@ class UsersViewSet(viewsets.ReadOnlyModelViewSet):
|
||||
def choose_users(zendesk: list, model: list) -> list:
|
||||
"""
|
||||
Функция формирует список пользователей, которые не зарегистрированы у нас.
|
||||
|
||||
:param zendesk: Список пользователей Zendesk
|
||||
:param model: Список пользователей (модель Userprofile)
|
||||
:return: Список
|
||||
@ -389,7 +402,8 @@ class UsersViewSet(viewsets.ReadOnlyModelViewSet):
|
||||
@staticmethod
|
||||
def get_zendesk_users(users: list) -> list:
|
||||
"""
|
||||
Получение списка пользователей Zendesk, не являющихся админами.
|
||||
Функция получения списка пользователей Zendesk, не являющихся админами.
|
||||
|
||||
:param users: Список пользователей
|
||||
:return: Список пользователей, не являющимися администраторами.
|
||||
"""
|
||||
@ -406,8 +420,8 @@ def statistic_page(request: WSGIRequest) -> HttpResponse:
|
||||
"""
|
||||
Функция отображения страницы статистики (для "superuser").
|
||||
|
||||
:param request: данные о пользователе: email, время и интервал работы. Данные получаем через forms.StatisticForm
|
||||
:return: адресация на страницу статистики
|
||||
:param request: Данные о пользователе: email, время и интервал работы. Данные получаем через forms.StatisticForm
|
||||
:return: Адресация на страницу статистики
|
||||
"""
|
||||
|
||||
# if not request.user.has_perm('main.has_control_access'):
|
||||
@ -439,5 +453,8 @@ def statistic_page(request: WSGIRequest) -> HttpResponse:
|
||||
context['form'] = form
|
||||
return render(request, 'pages/statistic.html', context)
|
||||
|
||||
def registration_failed(request):
|
||||
def registration_failed(request: WSGIRequest) -> HttpResponse:
|
||||
"""
|
||||
Функция отображения страницы "Регистрация закрыта".
|
||||
"""
|
||||
return render(request, 'pages/registration_failed.html')
|
||||
|
@ -32,7 +32,7 @@ class ZendeskAdmin:
|
||||
self.buffer_group_id= self.get_group(ZENDESK_GROUPS['buffer']).id
|
||||
self.solved_tickets_user_id = self.get_user(SOLVED_TICKETS_EMAIL).id
|
||||
|
||||
def update_user(self, user: ZenpyUser) -> bool:
|
||||
def update_user(self, user: ZenpyUser) -> None:
|
||||
"""
|
||||
Функция сохраняет изменение пользователя в Zendesk.
|
||||
|
||||
@ -40,7 +40,7 @@ class ZendeskAdmin:
|
||||
"""
|
||||
self.admin.users.update(user)
|
||||
|
||||
def update_tickets(self, tickets: List[ZenpyTicket]):
|
||||
def update_tickets(self, tickets: List[ZenpyTicket]) -> None:
|
||||
"""
|
||||
Функция сохраняет изменение тикетов в Zendesk.
|
||||
|
||||
@ -79,7 +79,7 @@ class ZendeskAdmin:
|
||||
return group
|
||||
return None
|
||||
|
||||
def get_user_org(self, email: str) -> str:
|
||||
def get_user_org(self, email: str) -> Optional[str]:
|
||||
"""
|
||||
Функция возвращает организацию, к которой относится пользователь по его email.
|
||||
|
||||
@ -96,7 +96,6 @@ class ZendeskAdmin:
|
||||
:raise: :class:`ValueError`: исключение, вызываемое если email не введен в env
|
||||
:raise: :class:`APIException`: исключение, вызываемое если пользователя с таким email не существует в Zendesk
|
||||
"""
|
||||
|
||||
if self.credentials.get('email') is None:
|
||||
raise ValueError('access_controller email not in env')
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user