Merge branch 'develop' into feature/pylint

# Conflicts:
#	main/tests.py
#	main/views.py
#	main/zendesk_admin.py
#	requirements/common.txt
This commit is contained in:
Andrew Smirnov 2021-05-13 20:45:06 +03:00
commit 839a333691
No known key found for this signature in database
GPG Key ID: 0EFE318E5BB2A82A
10 changed files with 429 additions and 68 deletions

View File

@ -46,9 +46,9 @@ cp .env.example .env
sudo apt install make sudo apt install make
pip install --upgrade pip pip install --upgrade pip
pip install -r requirements/dev.txt pip install -r requirements/dev.txt
(set -a && source .env && ./manage.py migrate) ./manage.py migrate
(set -a && source .env && ./manage.py loaddata data.json) ./manage.py loaddata data.json
(set -a && source .env && ./manage.py runserver) ./manage.py runserver
``` ```
## Перед запуском для тестирования: ## Перед запуском для тестирования:
@ -63,7 +63,7 @@ pip install -r requirements/dev.txt
- Перейти в папку приложения - Перейти в папку приложения
- Активировать виртуальное окружение - Активировать виртуальное окружение
- Выполнить команду `pip install -r requirements/dev.txt` - Выполнить команду `pip install -r requirements/dev.txt`
- В виртуальное окружение добавить следующие переменные: - В файл `.env` добавить следующие переменные:
``` ```

View File

@ -11,6 +11,7 @@ https://docs.djangoproject.com/en/3.1/ref/settings/
""" """
import os import os
from pathlib import Path from pathlib import Path
from dotenv import load_dotenv
# Build paths inside the project like this: BASE_DIR / 'subdir'. # Build paths inside the project like this: BASE_DIR / 'subdir'.
@ -20,6 +21,9 @@ BASE_DIR = Path(__file__).resolve().parent.parent
# Quick-start development settings - unsuitable for production # Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/3.1/howto/deployment/checklist/ # See https://docs.djangoproject.com/en/3.1/howto/deployment/checklist/
# Load environment variables from .env
load_dotenv()
# SECURITY WARNING: keep the secret key used in production secret! # SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = os.getenv('ACTRL_SECRET_KEY', 'empty') SECRET_KEY = os.getenv('ACTRL_SECRET_KEY', 'empty')

59
fixtures/profile.json Normal file
View File

@ -0,0 +1,59 @@
[
{
"model": "auth.user",
"pk": 1,
"fields": {
"password": "pbkdf2_sha256$216000$gHBBCr1jBELf$ZkEDW3IEd8Wij7u8vkv+0Eze32CS01bcaYWhcD9OIC4=",
"last_login": null,
"is_superuser": true,
"username": "idar.sokurov.05@mail.ru",
"first_name": "",
"last_name": "",
"email": "idar.sokurov.05@mail.ru",
"is_staff": true,
"is_active": true,
"date_joined": "2021-03-10T16:38:56.303Z",
"groups": [],
"user_permissions": [
33
]
}
},
{
"model": "main.userprofile",
"pk": 1,
"fields": {
"name": "ZendeskAdmin",
"user": 1,
"role": "admin"
}
},
{
"model": "auth.user",
"pk": 2,
"fields": {
"password": "pbkdf2_sha256$216000$5qLJgrm2Quq9$KDBNNymVZXkUx0HKBPFst2m83kLe0egPBnkW7KnkORU=",
"last_login": null,
"is_superuser": false,
"username": "krav-88@mail.ru",
"first_name": "",
"last_name": "",
"email": "krav-88@mail.ru",
"is_staff": false,
"is_active": true,
"date_joined": "2021-03-10T16:38:56.303Z",
"groups": [],
"user_permissions": []
}
},
{
"model": "main.userprofile",
"pk": 2,
"fields": {
"name": "UserForAccessTest",
"user": 2,
"role": "agent",
"custom_role_id": "360005209000"
}
}
]

View File

@ -12,8 +12,8 @@ from django.http import HttpResponseRedirect, HttpResponsePermanentRedirect
from django.shortcuts import redirect from django.shortcuts import redirect
from django.utils import timezone from django.utils import timezone
from zenpy import Zenpy from zenpy import Zenpy
from zenpy.lib.exception import APIException
from zenpy.lib.api_objects import User as ZenpyUser, Ticket as ZenpyTicket from zenpy.lib.api_objects import User as ZenpyUser, Ticket as ZenpyTicket
from zenpy.lib.exception import APIException
from zenpy.lib.generator import SearchResultGenerator from zenpy.lib.generator import SearchResultGenerator
from access_controller.settings import ZENDESK_ROLES as ROLES, ACTRL_ZENDESK_SUBDOMAIN from access_controller.settings import ZENDESK_ROLES as ROLES, ACTRL_ZENDESK_SUBDOMAIN

View File

@ -144,3 +144,23 @@ class StatisticForm(forms.Form):
} }
), ),
) )
class WorkGetTicketsForm(forms.Form):
"""
Форма получения количества тикетов для страницы work и work_get_tickets.
:param count_tickets: Поле для ввода количества тикетов
:type count_tickets: :class:`django.forms.fields.IntegerField`
"""
count_tickets = forms.IntegerField(
min_value=0,
max_value=100,
required=True,
widget=forms.NumberInput(
attrs={
'class': 'form-control mb-3',
'value': 1
}
),
)

View File

@ -66,8 +66,9 @@
<a href="/work/hand_over" class="hand-over-acess-button default-button">Сдать права инженера</a> <a href="/work/hand_over" class="hand-over-acess-button default-button">Сдать права инженера</a>
</div> </div>
<div class="col-10"> <div class="col-10">
<form method="GET" action="/work/get_tickets"> <form method="post" action="{% url 'work_get_tickets' %}">
<input class="form-control mb-3" type="number" min="1" value="1" name="count_tickets"> {% csrf_token %}
{{ get_tickets_form.count_tickets }}
<button type="submit" class="default-button">Взять тикеты в работу</button> <button type="submit" class="default-button">Взять тикеты в работу</button>
</form> </form>
</div> </div>

View File

@ -3,11 +3,13 @@
""" """
from unittest.mock import patch import random
from urllib.parse import urlparse from unittest.mock import patch, Mock
from django.contrib.auth import get_user_model from django.contrib.auth import get_user_model
from django.core import mail from django.core import mail
from django.http import HttpResponseRedirect
from django.template.loader import render_to_string
from django.test import TestCase, Client from django.test import TestCase, Client
from django.urls import reverse, reverse_lazy from django.urls import reverse, reverse_lazy
from django.utils import translation from django.utils import translation
@ -55,42 +57,23 @@ class RegistrationTestCase(TestCase):
resp = self.client.post(reverse('registration'), data={'email': '123@test.ru'}) resp = self.client.post(reverse('registration'), data={'email': '123@test.ru'})
self.assertContains(resp, 'Этот адрес электронной почты уже используется', count=1, status_code=200) self.assertContains(resp, 'Этот адрес электронной почты уже используется', count=1, status_code=200)
def test_registration_email_sending(self): def test_registration_send_email(self):
""" """
Функция тестирования отправки email. Функция тестирования отправки email.
# TODO: Найти способ лучше проверять сообщения
""" """
email_template = [ with self.settings(EMAIL_BACKEND=self.email_backend):
'', response: HttpResponseRedirect = \
'Вы получили это письмо, потому что вы (или кто-то другой) запросили восстановление пароля '
'от учётной записи на сайте testserver, которая связана с этим адресом электронной почты.',
'',
'Пожалуйста, перейдите на эту страницу и введите новый пароль:',
'',
'url',
'',
f'Ваше имя пользователя (на случай, если вы его забыли): {self.any_zendesk_user_email}',
'',
'Спасибо, что используете наш сайт!',
'',
'Команда сайта testserver',
'',
'',
'',
]
with self.settings(EMAIL_BACKEND=self.email_backend) and translation.override('ru'):
self.client.post(reverse('registration'), data={'email': self.any_zendesk_user_email}) self.client.post(reverse('registration'), data={'email': self.any_zendesk_user_email})
self.assertEqual(response.status_code, 302)
self.assertEqual(len(mail.outbox), 1) self.assertEqual(len(mail.outbox), 1)
self.assertEqual(mail.outbox[0].to, [self.zendesk_admin_email]) self.assertEqual(mail.outbox[0].to, [self.any_zendesk_user_email])
self.assertEqual(mail.outbox[0].from_email, sets.DEFAULT_FROM_EMAIL)
message = mail.outbox[0].body.split('\n') # context that the email template was rendered with
for i in enumerate(message): email_context = response.context[0].dicts[1]
if email_template[i] != 'url': correct_subject = render_to_string('registration/password_reset_subject.txt', email_context, response.request)
self.assertEqual(message[i], email_template[i]) self.assertEqual(mail.outbox[0].subject, correct_subject.strip())
else: correct_body = render_to_string('registration/password_reset_email.html', email_context, response.request)
self.assertTrue(urlparse(message[i]).scheme) self.assertEqual(mail.outbox[0].body, correct_body)
def test_registration_user_creating(self): def test_registration_user_creating(self):
""" """
@ -202,3 +185,284 @@ class MakeEngineerTestCase(TestCase):
self.assertEqual(len(call_list), 2) self.assertEqual(len(call_list), 2)
for obj in mock_objects: for obj in mock_objects:
self.assertEqual(obj[0][0].custom_role_id, sets.ZENDESK_ROLES['engineer']) self.assertEqual(obj[0][0].custom_role_id, sets.ZENDESK_ROLES['engineer'])
class PasswordResetTestCase(TestCase):
fixtures = ['fixtures/test_make_engineer.json']
def setUp(self):
self.user = '123@test.ru'
self.email_backend = 'django.core.mail.backends.locmem.EmailBackend'
self.client = Client()
self.client.force_login(User.objects.get(email=self.user))
def test_redirect(self):
with self.settings(EMAIL_BACKEND=self.email_backend):
resp = self.client.post(reverse_lazy('password_reset'), data={'email': self.user})
self.assertRedirects(resp, reverse('password_reset_done'))
self.assertEqual(resp.status_code, 302)
def test_send_email(self):
with self.settings(EMAIL_BACKEND=self.email_backend):
response: HttpResponseRedirect = \
self.client.post(reverse_lazy('password_reset'), data={'email': self.user})
self.assertEqual(response.status_code, 302)
self.assertEqual(len(mail.outbox), 1)
self.assertEqual(mail.outbox[0].to, [self.user])
# context that the email template was rendered with
email_context = response.context[0].dicts[1]
correct_subject = render_to_string('registration/password_reset_subject.txt', email_context, response.request)
self.assertEqual(mail.outbox[0].subject, correct_subject.strip())
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):
with self.settings(EMAIL_BACKEND=self.email_backend) and translation.override('ru'):
resp = self.client.post(reverse_lazy('password_reset'), data={'email': 1})
self.assertContains(resp, 'Введите правильный адрес электронной почты.', count=1, status_code=200)
def test_user_does_not_exist(self):
with self.settings(EMAIL_BACKEND=self.email_backend):
resp = self.client.post(reverse_lazy('password_reset'), data={'email': self.user + str(random.random())})
self.assertRedirects(resp, reverse('password_reset_done'))
self.assertEqual(resp.status_code, 302)
self.assertEqual(len(mail.outbox), 0)
class PasswordChangeTestCase(TestCase):
fixtures = ['fixtures/test_make_engineer.json']
def setUp(self):
self.user = '123@test.ru'
self.client = Client()
self.client.force_login(User.objects.get(email=self.user))
self.set_password()
def set_password(self):
user: User = User.objects.get(email=self.user)
user.set_password('ImpossiblyHardPassword')
user.save()
self.client.force_login(User.objects.get(email=self.user))
def test_change_successful(self):
self.client.post(
reverse_lazy('password_change'),
data={
'old_password': 'ImpossiblyHardPassword',
'new_password1': 'EasyPassword',
'new_password2': 'EasyPassword',
}
)
user = User.objects.get(email=self.user)
self.assertTrue(user.check_password('EasyPassword'))
def test_invalid_old_password(self):
with translation.override('ru'):
resp = self.client.post(
reverse_lazy('password_change'),
data={
'old_password': 'EasyPassword',
'new_password1': 'EasyPassword',
'new_password2': 'EasyPassword',
}
)
self.assertContains(resp, 'Ваш старый пароль введен неправильно', count=1, status_code=200)
def test_different_new_passwords(self):
with translation.override('ru'):
resp = self.client.post(
reverse_lazy('password_change'),
data={
'old_password': 'ImpossiblyHardPassword',
'new_password1': 'EasyPassword',
'new_password2': 'EasyPassword1',
}
)
self.assertContains(resp, 'Введенные пароли не совпадают', count=1, status_code=200)
def test_invalid_new_password1(self):
with translation.override('ru'):
resp = self.client.post(
reverse_lazy('password_change'),
data={
'old_password': 'ImpossiblyHardPassword',
'new_password1': 'short',
'new_password2': 'short',
}
)
self.assertContains(resp, 'Введённый пароль слишком короткий', count=1, status_code=200)
def test_invalid_new_password2(self):
with translation.override('ru'):
resp = self.client.post(
reverse_lazy('password_change'),
data={
'old_password': 'ImpossiblyHardPassword',
'new_password1': '123123123123123123132123123',
'new_password2': '123123123123123123132123123',
}
)
self.assertContains(resp, 'Введённый пароль состоит только из цифр', count=1, status_code=200)
def test_invalid_new_password3(self):
with translation.override('ru'):
resp = self.client.post(
reverse_lazy('password_change'),
data={
'old_password': 'ImpossiblyHardPassword',
'new_password1': self.user,
'new_password2': self.user,
}
)
self.assertContains(resp, 'Введённый пароль слишком похож на имя пользователя', count=1, status_code=200)
class GetTicketsTestCase(TestCase):
"""
Класс тестов для проверки функции получения тикетов.
"""
fixtures = ['fixtures/test_make_engineer.json']
def setUp(self):
"""
Предустановленные значения для проведения тестов.
"""
self.light_agent = '123@test.ru'
self.engineer = 'customer@example.com'
self.client = Client()
self.client.force_login(User.objects.get(email=self.engineer))
self.light_agent_client = Client()
self.light_agent_client.force_login(User.objects.get(email=self.light_agent))
@patch('main.views.zenpy.get_user')
@patch('main.extra_func.zenpy')
def test_redirect(self, ZenpyMock, GetUserMock):
"""
Функция проверки переадресации пользователя на рабочую страницу.
"""
GetUserMock.return_value = Mock()
user = User.objects.get(email=self.engineer)
resp = self.client.post(reverse('work_get_tickets'))
self.assertRedirects(resp, reverse('work', args=[user.id]))
self.assertEqual(resp.status_code, 302)
@patch('main.views.zenpy')
@patch('main.views.get_tickets_list_for_group')
def test_take_one_ticket(self, TicketsMock, ZenpyViewsMock):
"""
Функция проверки назначения одного тикета на engineer.
"""
TicketsMock.return_value = [Mock()]
ZenpyViewsMock.get_user.return_value = Mock(role='agent', custom_role_id=sets.ZENDESK_ROLES['engineer'])
self.client.post(reverse('work_get_tickets'), data={'count_tickets': 1})
tickets = ZenpyViewsMock.update_tickets.call_args
self.assertEqual(tickets[0][0][0].assignee, ZenpyViewsMock.get_user.return_value)
@patch('main.views.get_tickets_list_for_group')
@patch('main.views.zenpy')
def test_take_many_tickets(self, ZenpyMock, TicketsMock):
"""
Функция проверки назначения нескольких тикетов на engineer.
"""
TicketsMock.return_value = [Mock()] * 3
ZenpyMock.get_user.return_value = Mock(role='agent', custom_role_id=sets.ZENDESK_ROLES['engineer'])
self.client.post(reverse('work_get_tickets'), data={'count_tickets': 3})
tickets = ZenpyMock.update_tickets.call_args
for ticket in tickets[0][0]:
self.assertEqual(ticket.assignee, ZenpyMock.get_user.return_value)
@patch('main.views.zenpy.get_user')
@patch('main.views.zenpy')
def test_light_agent_take_ticket(self, ZenpyMock, GetUserMock):
"""
Функция проверки попытки назначения тикета на light_agent.
"""
GetUserMock.return_value = Mock(role='agent', custom_role_id=sets.ZENDESK_ROLES['light_agent'])
self.light_agent_client.post(reverse('work_get_tickets'), data={'count_tickets': 3})
tickets = ZenpyMock.update_tickets.call_args
self.assertIsNone(tickets)
@patch('main.views.zenpy')
@patch('main.views.get_tickets_list_for_group')
def test_take_zero_tickets(self, TicketsMock, ZenpyMock):
"""
Функция проверки попытки назначения нуля тикета на engineer.
"""
TicketsMock.return_value = [Mock()] * 3
ZenpyMock.get_user.return_value = Mock(role='agent', custom_role_id=sets.ZENDESK_ROLES['engineer'])
self.client.post(reverse('work_get_tickets'), data={'count_tickets': 0})
tickets = ZenpyMock.update_tickets.call_args[0][0]
self.assertListEqual(tickets, [])
@patch('main.views.get_tickets_list_for_group')
@patch('main.views.zenpy')
def test_take_invalid_count_tickets(self, ZenpyMock, TicketsMock, ):
"""
Функция проверки попытки назначения нуля тикетов на engineer.
"""
TicketsMock.return_value = [Mock()] * 3
ZenpyMock.get_user.return_value = Mock(role='agent', custom_role_id=sets.ZENDESK_ROLES['engineer'])
self.client.post(reverse('work_get_tickets'), data={'count_tickets': 'asd'})
tickets = ZenpyMock.update_tickets.call_args
self.assertIsNone(tickets)
class ProfileTestCase(TestCase):
"""
Класс тестов для проверки синхронизации профиля пользователя.
"""
fixtures = ['fixtures/profile.json']
def setUp(self):
"""
Предустановленные значения для проведения тестов.
"""
self.zendesk_agent_email = 'krav-88@mail.ru'
self.zendesk_admin_email = 'idar.sokurov.05@mail.ru'
self.client = Client()
self.client.force_login(User.objects.get(email=self.zendesk_agent_email))
self.admin_client = Client()
self.admin_client.force_login(User.objects.get(email=self.zendesk_admin_email))
def test_correct_username(self):
"""
Функция проверки синхронизации имени пользователя.
"""
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):
"""
Функция проверки синхронизации почты пользователя.
"""
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):
"""
Функция проверки синхронизации роли пользователя.
"""
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):
"""
Функция проверки синхронизации рабочей роли пользователя.
"""
resp = self.client.get(reverse('profile'))
user = zenpy.get_user(self.zendesk_agent_email)
self.assertEqual(resp.context['profile'].custom_role_id, user.custom_role_id if user.custom_role_id else 0)
resp = self.admin_client.get(reverse('profile'))
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):
"""
Функция проверки синхронизации изображения пользователя.
"""
resp = self.client.get(reverse('profile'))
user = zenpy.get_user(self.zendesk_agent_email)
self.assertEqual(resp.context['profile'].image, user.photo['content_url'] if user.photo else None)

View File

@ -7,12 +7,12 @@ from smtplib import SMTPException
from typing import Dict, Any, Optional from typing import Dict, Any, Optional
from django.contrib import messages from django.contrib import messages
from django.contrib.auth.decorators import login_required
from django.contrib.auth.mixins import LoginRequiredMixin, PermissionRequiredMixin
from django.contrib.auth import get_user_model from django.contrib.auth import get_user_model
from django.contrib.auth.decorators import login_required
from django.contrib.auth.forms import PasswordResetForm
from django.contrib.auth.mixins import LoginRequiredMixin, PermissionRequiredMixin
from django.contrib.auth.models import Permission from django.contrib.auth.models import Permission
from django.contrib.auth.tokens import default_token_generator from django.contrib.auth.tokens import default_token_generator
from django.contrib.auth.forms import PasswordResetForm
from django.contrib.auth.views import LoginView from django.contrib.auth.views import LoginView
from django.contrib.contenttypes.models import ContentType from django.contrib.contenttypes.models import ContentType
from django.contrib.messages.views import SuccessMessageMixin from django.contrib.messages.views import SuccessMessageMixin
@ -22,7 +22,7 @@ from django.shortcuts import render, redirect
from django.urls import reverse_lazy from django.urls import reverse_lazy
from django.views.generic import FormView from django.views.generic import FormView
from django_registration.views import RegistrationView from django_registration.views import RegistrationView
# Django REST
from rest_framework import viewsets from rest_framework import viewsets
from rest_framework.response import Response from rest_framework.response import Response
@ -30,12 +30,12 @@ from access_controller.settings import DEFAULT_FROM_EMAIL, ZENDESK_ROLES, ZENDES
from main.extra_func import check_user_exist, update_profile, get_user_organization, \ from main.extra_func import check_user_exist, update_profile, get_user_organization, \
make_engineer, make_light_agent, get_users_list, update_users_in_model, count_users, \ make_engineer, make_light_agent, get_users_list, update_users_in_model, count_users, \
set_session_params_for_work_page, get_tickets_list_for_group set_session_params_for_work_page, get_tickets_list_for_group
from main.zendesk_admin import zenpy from main.forms import AdminPageUsers, CustomRegistrationForm, CustomAuthenticationForm, \
from main.forms import AdminPageUsers, CustomRegistrationForm, CustomAuthenticationForm, StatisticForm StatisticForm, WorkGetTicketsForm
from main.serializers import ProfileSerializer, ZendeskUserSerializer from main.serializers import ProfileSerializer, ZendeskUserSerializer
from .statistic_data import StatisticData from main.zendesk_admin import zenpy
from .models import UserProfile from .models import UserProfile
from .statistic_data import StatisticData
def setup_context(**kwargs) -> Dict[str, Any]: def setup_context(**kwargs) -> Dict[str, Any]:
@ -216,6 +216,7 @@ def work_page(request: WSGIRequest, required_id: int) -> HttpResponse:
'messages': messages.get_messages(request), 'messages': messages.get_messages(request),
'licences_remaining': max(0, ZENDESK_MAX_AGENTS - len(engineers)), 'licences_remaining': max(0, ZENDESK_MAX_AGENTS - len(engineers)),
'pagename': 'Управление правами', 'pagename': 'Управление правами',
'get_tickets_form': WorkGetTicketsForm()
} }
return render(request, 'pages/work.html', context) return render(request, 'pages/work.html', context)
return redirect("login") return redirect("login")
@ -254,21 +255,18 @@ def work_get_tickets(request: WSGIRequest) -> HttpResponse:
:return: :return:
""" """
zenpy_user = zenpy.get_user(request.user.email) zenpy_user = zenpy.get_user(request.user.email)
if request.method == 'POST':
if zenpy_user.role == 'admin' or zenpy_user.custom_role_id == ZENDESK_ROLES['engineer']: if zenpy_user.role == 'admin' or zenpy_user.custom_role_id == ZENDESK_ROLES['engineer']:
form = WorkGetTicketsForm(request.POST)
if form.is_valid():
tickets = get_tickets_list_for_group(ZENDESK_GROUPS['buffer']) tickets = get_tickets_list_for_group(ZENDESK_GROUPS['buffer'])
assigned_tickets = [] assigned_tickets = []
count = 0 for i in range(min(form.cleaned_data['count_tickets'], len(tickets))):
for i in enumerate(tickets):
if i == int(request.GET.get('count_tickets')):
if assigned_tickets:
zenpy.admin.tickets.update(assigned_tickets)
return set_session_params_for_work_page(request, count)
tickets[i].assignee = zenpy_user tickets[i].assignee = zenpy_user
assigned_tickets.append(tickets[i]) assigned_tickets.append(tickets[i])
count += 1 zenpy.update_tickets(assigned_tickets)
if assigned_tickets: return set_session_params_for_work_page(request, len(assigned_tickets))
zenpy.admin.tickets.update(assigned_tickets)
return set_session_params_for_work_page(request, count)
return set_session_params_for_work_page(request, is_confirm=False) return set_session_params_for_work_page(request, is_confirm=False)

View File

@ -2,10 +2,12 @@
Функционал работы администратора Zendesk. Функционал работы администратора Zendesk.
""" """
from typing import Optional, Dict from typing import Optional, Dict, List
from zenpy import Zenpy from zenpy import Zenpy
from zenpy.lib.api_objects import User as ZenpyUser, Group as ZenpyGroup from zenpy.lib.api_objects import User as ZenpyUser, Group as ZenpyGroup, Ticket as ZenpyTicket
from zenpy.lib.exception import APIException from zenpy.lib.exception import APIException
from access_controller.settings import ACTRL_ZENDESK_SUBDOMAIN, ACTRL_API_EMAIL, ACTRL_API_TOKEN, ACTRL_API_PASSWORD, \ from access_controller.settings import ACTRL_ZENDESK_SUBDOMAIN, ACTRL_API_EMAIL, ACTRL_API_TOKEN, ACTRL_API_PASSWORD, \
ZENDESK_GROUPS, SOLVED_TICKETS_EMAIL ZENDESK_GROUPS, SOLVED_TICKETS_EMAIL
@ -38,6 +40,15 @@ class ZendeskAdmin:
""" """
self.admin.users.update(user) self.admin.users.update(user)
def update_tickets(self, tickets: List[ZenpyTicket]):
"""
Функция сохраняет изменение тикетов в Zendesk.
:param tickets: Тикеты с изменёнными данными
"""
if tickets:
self.admin.tickets.update(tickets)
def check_user(self, email: str) -> bool: def check_user(self, email: str) -> bool:
""" """
Функция осуществляет проверку существования пользователя в Zendesk по email. Функция осуществляет проверку существования пользователя в Zendesk по email.

View File

@ -7,7 +7,6 @@ zenpy~=2.0.24
django_registration==3.1.1 django_registration==3.1.1
djangorestframework==3.12.2 djangorestframework==3.12.2
# Documentation # Documentation
Sphinx==3.4.3 Sphinx==3.4.3
sphinx-rtd-theme==0.5.1 sphinx-rtd-theme==0.5.1
@ -15,6 +14,11 @@ sphinx-autodoc-typehints==1.11.1
pyenchant==3.2.0 pyenchant==3.2.0
sphinxcontrib-spelling==7.1.0 sphinxcontrib-spelling==7.1.0
m2r == 0.2.1 m2r == 0.2.1
# Code style
pylint == 2.8.2 pylint == 2.8.2
pylint-django == 2.4.4 pylint-django == 2.4.4
autopep8 == 1.5.6 autopep8 == 1.5.6
# Misc
python-dotenv==0.17.1