Add get tickets tests

This commit is contained in:
Сокуров Идар 2021-05-13 04:49:02 +00:00 committed by Татищев Юрий
parent 16feae1bf1
commit 76cd782ff4
6 changed files with 151 additions and 32 deletions

View File

@ -6,8 +6,8 @@ from django.core.exceptions import ObjectDoesNotExist
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

@ -140,3 +140,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,10 +66,11 @@
<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 %}
<button type="submit" class="default-button">Взять тикеты в работу</button> {{ get_tickets_form.count_tickets }}
</form> <button type="submit" class="default-button">Взять тикеты в работу</button>
</form>
</div> </div>
{% for message in messages %} {% for message in messages %}
<script>create_notification('{{message}}','','{{message.tags}}',2000)</script> <script>create_notification('{{message}}','','{{message.tags}}',2000)</script>

View File

@ -1,5 +1,5 @@
import random import random
from unittest.mock import patch from unittest.mock import patch, Mock
from django.contrib.auth.models import User from django.contrib.auth.models import User
from django.core import mail from django.core import mail
@ -43,7 +43,7 @@ class RegistrationTestCase(TestCase):
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(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])
# context that the email template was rendered with # context that the email template was rendered with
email_context = response.context[0].dicts[1] email_context = response.context[0].dicts[1]
@ -262,3 +262,93 @@ class PasswordChangeTestCase(TestCase):
} }
) )
self.assertContains(resp, 'Введённый пароль слишком похож на имя пользователя', count=1, status_code=200) 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)

View File

@ -1,19 +1,18 @@
from smtplib import SMTPException from smtplib import SMTPException
from typing import Dict, Any
from django.contrib import messages from django.contrib import messages
from django.contrib.auth.decorators import login_required 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.mixins import LoginRequiredMixin, PermissionRequiredMixin
from django.contrib.auth.models import User, Permission from django.contrib.auth.models import User, 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
from django.core.handlers.wsgi import WSGIRequest from django.core.handlers.wsgi import WSGIRequest
from django.http import HttpResponseRedirect, HttpResponse from django.http import HttpResponseRedirect, HttpResponse
from django.shortcuts import render, redirect from django.shortcuts import render, redirect
from django.urls import reverse_lazy, reverse 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 # Django REST
@ -23,13 +22,13 @@ from rest_framework.response import Response
from access_controller.settings import DEFAULT_FROM_EMAIL, ZENDESK_ROLES, ZENDESK_MAX_AGENTS, ZENDESK_GROUPS from access_controller.settings import DEFAULT_FROM_EMAIL, ZENDESK_ROLES, ZENDESK_MAX_AGENTS, ZENDESK_GROUPS
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, \
log, set_session_params_for_work_page, get_tickets_list_for_group set_session_params_for_work_page, get_tickets_list_for_group
from .statistic_data import StatisticData from main.forms import AdminPageUsers, CustomRegistrationForm, CustomAuthenticationForm, StatisticForm, \
from main.zendesk_admin import zenpy WorkGetTicketsForm
from main.requester import TicketListRequester
from main.forms import AdminPageUsers, CustomRegistrationForm, CustomAuthenticationForm, StatisticForm
from main.serializers import ProfileSerializer, ZendeskUserSerializer from main.serializers import ProfileSerializer, ZendeskUserSerializer
from main.zendesk_admin import zenpy
from .models import UserProfile from .models import UserProfile
from .statistic_data import StatisticData
class CustomRegistrationView(RegistrationView): class CustomRegistrationView(RegistrationView):
@ -178,6 +177,7 @@ def work_page(request: WSGIRequest, 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")
@ -211,21 +211,18 @@ def work_become_engineer(request: WSGIRequest) -> HttpResponseRedirect:
@login_required() @login_required()
def work_get_tickets(request): def work_get_tickets(request):
zenpy_user = zenpy.get_user(request.user.email) zenpy_user = zenpy.get_user(request.user.email)
if zenpy_user.role == 'admin' or zenpy_user.custom_role_id == ZENDESK_ROLES['engineer']:
tickets = get_tickets_list_for_group(ZENDESK_GROUPS['buffer']) if request.method == 'POST':
assigned_tickets = [] if zenpy_user.role == 'admin' or zenpy_user.custom_role_id == ZENDESK_ROLES['engineer']:
count = 0 form = WorkGetTicketsForm(request.POST)
for i in range(len(tickets)): if form.is_valid():
if i == int(request.GET.get('count_tickets')): tickets = get_tickets_list_for_group(ZENDESK_GROUPS['buffer'])
if assigned_tickets: assigned_tickets = []
zenpy.admin.tickets.update(assigned_tickets) for i in range(min(form.cleaned_data['count_tickets'], len(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]) zenpy.update_tickets(assigned_tickets)
count += 1 return set_session_params_for_work_page(request, len(assigned_tickets))
if 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

@ -1,7 +1,9 @@
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
@ -28,6 +30,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.