From 66339c4f6be83776c46e1c7aabe93f6e2f29c46c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=A1=D0=BE=D0=BA=D1=83=D1=80=D0=BE=D0=B2=20=D0=98=D0=B4?= =?UTF-8?q?=D0=B0=D1=80?= Date: Wed, 5 May 2021 23:44:24 +0000 Subject: [PATCH 1/3] Add registration tests --- access_controller/settings.py | 26 +++++------ access_controller/urls.py | 1 + fixtures/data.json | 57 ++++++++++++++++++++++++ main/tests.py | 81 +++++++++++++++++++++++++++++++++++ main/views.py | 2 +- 5 files changed, 153 insertions(+), 14 deletions(-) create mode 100644 fixtures/data.json diff --git a/access_controller/settings.py b/access_controller/settings.py index a7585ed..a74ad7f 100644 --- a/access_controller/settings.py +++ b/access_controller/settings.py @@ -19,10 +19,10 @@ BASE_DIR = Path(__file__).resolve().parent.parent # See https://docs.djangoproject.com/en/3.1/howto/deployment/checklist/ # 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') # SECURITY WARNING: don't run with debug turned on in production! -DEBUG = bool(int(os.getenv('ACTRL_DEBUG',1))) +DEBUG = bool(int(os.getenv('ACTRL_DEBUG', 1))) ALLOWED_HOSTS = [ '127.0.0.1', @@ -57,13 +57,13 @@ MIDDLEWARE = [ ROOT_URLCONF = 'access_controller.urls' EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend' -EMAIL_HOST = os.getenv('ACTRL_EMAIL_HOST','smtp.gmail.com') -EMAIL_PORT = int(os.getenv('ACTRL_EMAIL_PORT',587)) -EMAIL_USE_TLS = bool(int(os.getenv('ACTRL_EMAIL_TLS',1))) -EMAIL_HOST_USER = os.getenv('ACTRL_EMAIL_HOST_USER','group02django@gmail.com') -EMAIL_HOST_PASSWORD = os.getenv('ACTRL_EMAIL_HOST_PASSWORD','djangogroup02') -DEFAULT_FROM_EMAIL = os.getenv('ACTRL_FROM_EMAIL',EMAIL_HOST_USER) -SERVER_EMAIL = os.getenv('ACTRL_SERVER_EMAIL',EMAIL_HOST_USER) +EMAIL_HOST = os.getenv('ACTRL_EMAIL_HOST', 'smtp.gmail.com') +EMAIL_PORT = int(os.getenv('ACTRL_EMAIL_PORT', 587)) +EMAIL_USE_TLS = bool(int(os.getenv('ACTRL_EMAIL_TLS', 1))) +EMAIL_HOST_USER = os.getenv('ACTRL_EMAIL_HOST_USER', 'group02django@gmail.com') +EMAIL_HOST_PASSWORD = os.getenv('ACTRL_EMAIL_HOST_PASSWORD', 'djangogroup02') +DEFAULT_FROM_EMAIL = os.getenv('ACTRL_FROM_EMAIL', EMAIL_HOST_USER) +SERVER_EMAIL = os.getenv('ACTRL_SERVER_EMAIL', EMAIL_HOST_USER) TEMPLATES = [ { @@ -150,8 +150,8 @@ AUTHENTICATION_BACKENDS = [ ZENDESK_ROLES = { - 'engineer': int(os.getenv('ENG_CROLE_ID',0)), - 'light_agent': int(os.getenv('LA_CROLE_ID',0)), + 'engineer': int(os.getenv('ENG_CROLE_ID', 0)), + 'light_agent': int(os.getenv('LA_CROLE_ID', 0)), } ZENDESK_GROUPS = { @@ -161,7 +161,7 @@ ZENDESK_GROUPS = { SOLVED_TICKETS_EMAIL = os.getenv('ST_EMAIL') -ZENDESK_MAX_AGENTS = int(os.getenv('LICENSE_NO',0)) +ZENDESK_MAX_AGENTS = int(os.getenv('LICENSE_NO', 0)) REST_FRAMEWORK = { # Use Django's standard `django.contrib.auth` permissions, @@ -171,7 +171,7 @@ REST_FRAMEWORK = { ] } -ONE_DAY = int(os.getenv('SHIFTH',0)) # Количество часов в 1 рабочем дне +ONE_DAY = int(os.getenv('SHIFTH', 0)) # Количество часов в 1 рабочем дне ACTRL_ZENDESK_SUBDOMAIN = os.getenv('ACTRL_ZENDESK_SUBDOMAIN') or os.getenv('ZD_DOMAIN') ACTRL_API_EMAIL = os.getenv('ACTRL_API_EMAIL') or os.getenv('ACCESS_CONTROLLER_API_EMAIL') diff --git a/access_controller/urls.py b/access_controller/urls.py index 63dc19f..7df57b3 100644 --- a/access_controller/urls.py +++ b/access_controller/urls.py @@ -22,6 +22,7 @@ from main.views import work_page, work_hand_over, work_become_engineer, work_get AdminPageView, statistic_page from main.urls import router + urlpatterns = [ path('admin/', admin.site.urls, name='admin'), path('', main_page, name='index'), diff --git a/fixtures/data.json b/fixtures/data.json new file mode 100644 index 0000000..a4310a4 --- /dev/null +++ b/fixtures/data.json @@ -0,0 +1,57 @@ +[ + { + "model": "auth.user", + "pk": 1, + "fields": { + "password": "pbkdf2_sha256$216000$gHBBCr1jBELf$ZkEDW3IEd8Wij7u8vkv+0Eze32CS01bcaYWhcD9OIC4=", + "last_login": null, + "is_superuser": true, + "username": "admin@gmail.com", + "first_name": "", + "last_name": "", + "email": "admin@gmail.com", + "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": "123@test.ru", + "first_name": "", + "last_name": "", + "email": "123@test.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" + } + } +] diff --git a/main/tests.py b/main/tests.py index b733ed1..c06bc21 100644 --- a/main/tests.py +++ b/main/tests.py @@ -1,2 +1,83 @@ +from urllib.parse import urlparse + +from django.contrib.auth.models import User +from django.core import mail from django.test import TestCase, Client +from django.urls import reverse +from django.utils import translation + import access_controller.settings as sets +from main.zendesk_admin import zenpy + + +class RegistrationTestCase(TestCase): + fixtures = ['fixtures/data.json'] + + def setUp(self): + self.email_backend = 'django.core.mail.backends.locmem.EmailBackend' + self.any_zendesk_user_email = 'idar.sokurov.05@mail.ru' + self.zendesk_admin_email = 'idar.sokurov.05@mail.ru' + self.client = Client() + + def test_registration_complete_redirect(self): + 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): + 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): + 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_email_sending(self): + # TODO: Найти способ лучше проверять сообщения + email_template = [ + '', + 'Вы получили это письмо, потому что вы (или кто-то другой) запросили восстановление пароля ' + 'от учётной записи на сайте 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.assertEqual(len(mail.outbox), 1) + self.assertEqual(mail.outbox[0].to, [self.zendesk_admin_email]) + self.assertEqual(mail.outbox[0].from_email, sets.DEFAULT_FROM_EMAIL) + + message = mail.outbox[0].body.split('\n') + for i in range(len(message)): + if email_template[i] != 'url': + self.assertEqual(message[i], email_template[i]) + else: + self.assertTrue(urlparse(message[i]).scheme) + + def test_registration_user_creating(self): + with self.settings(EMAIL_BACKEND=self.email_backend): + self.client.post(reverse('registration'), data={'email': self.any_zendesk_user_email}) + user = User.objects.get(email=self.any_zendesk_user_email) + zendesk_user = zenpy.get_user(self.any_zendesk_user_email) + self.assertEqual(user.userprofile.name, zendesk_user.name) + + def test_permissions_applying(self): + with self.settings(EMAIL_BACKEND=self.email_backend): + self.client.post(reverse('registration'), data={'email': self.zendesk_admin_email}) + user = User.objects.get(email=self.zendesk_admin_email) + self.assertEqual(user.userprofile.role, 'admin') + self.assertTrue(user.has_perm('main.has_control_access')) diff --git a/main/views.py b/main/views.py index d21a6e9..bd57eab 100644 --- a/main/views.py +++ b/main/views.py @@ -105,7 +105,7 @@ class CustomRegistrationView(RegistrationView): except SMTPException: self.redirect_url = 'email_sending_error' else: - raise ValueError('Непредвиденная ошибка') + self.redirect_url = 'email_sending_error' else: self.redirect_url = 'invalid_zendesk_email' From f77256937ed2ad25c53d7100fbfc5cf261960f45 Mon Sep 17 00:00:00 2001 From: Timofey Mazurov Date: Thu, 6 May 2021 02:44:53 +0300 Subject: [PATCH 2/3] Added logging for work pages --- main/extra_func.py | 10 ++++++---- main/views.py | 2 -- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/main/extra_func.py b/main/extra_func.py index 0c93ba1..c41625a 100644 --- a/main/extra_func.py +++ b/main/extra_func.py @@ -16,12 +16,13 @@ from main.models import UserProfile, RoleChangeLogs, UnassignedTicket, Unassigne from main.zendesk_admin import zenpy -def update_role(user_profile: UserProfile, role: int) -> None: +def update_role(user_profile: UserProfile, role: int, who_changes: User) -> None: """ Функция меняет роль пользователя. :param user_profile: Профиль пользователя :param role: Новая роль + :param who_changes: Пользователь, меняющий роль :return: Пользователь с обновленной ролью """ zendesk = zenpy @@ -29,6 +30,7 @@ def update_role(user_profile: UserProfile, role: int) -> None: user.custom_role_id = role user_profile.custom_role_id = role user_profile.save() + log(user_profile, who_changes.userprofile) zendesk.admin.users.update(user) @@ -39,7 +41,7 @@ def make_engineer(user_profile: UserProfile, who_changes: User) -> None: :param user_profile: Профиль пользователя :return: Вызов функции **update_role** с параметрами: профиль пользователя, роль "engineer" """ - update_role(user_profile, ROLES['engineer']) + update_role(user_profile, ROLES['engineer'], who_changes) def make_light_agent(user_profile: UserProfile, who_changes: User) -> None: @@ -69,7 +71,7 @@ def make_light_agent(user_profile: UserProfile, who_changes: User) -> None: attempts, success = 5, False while not success and attempts != 0: try: - update_role(user_profile, ROLES['light_agent']) + update_role(user_profile, ROLES['light_agent'], who_changes) success = True except APIException as e: attempts -= 1 @@ -534,7 +536,7 @@ class CsvFormatter(logging.Formatter): return msg -def log(user, admin=0): +def log(user, admin=None): """ Осуществляет запись логов в базу данных и csv файл :param admin: diff --git a/main/views.py b/main/views.py index d21a6e9..67ab7ea 100644 --- a/main/views.py +++ b/main/views.py @@ -289,7 +289,6 @@ class AdminPageView(LoginRequiredMixin, PermissionRequiredMixin, SuccessMessageM """ for user in users: make_engineer(user, self.request.user) - log(user, self.request.user.userprofile) def make_light_agents(self, users): """ @@ -300,7 +299,6 @@ class AdminPageView(LoginRequiredMixin, PermissionRequiredMixin, SuccessMessageM """ for user in users: make_light_agent(user, self.request.user) - log(user, self.request.user.userprofile) class CustomLoginView(LoginView): From 0086d4909e37666cd5c6229235711e1d4ab45413 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=A1=D0=BE=D0=BA=D1=83=D1=80=D0=BE=D0=B2=20=D0=98=D0=B4?= =?UTF-8?q?=D0=B0=D1=80?= Date: Thu, 6 May 2021 15:22:57 +0000 Subject: [PATCH 3/3] Feature/tests/make_eng from work and control pages --- access_controller/urls.py | 1 - fixtures/test_make_engineer.json | 85 +++++++++++++++++++++++++++ main/extra_func.py | 2 +- main/templates/pages/adm_ruleset.html | 4 +- main/tests.py | 69 +++++++++++++++++++++- main/zendesk_admin.py | 9 ++- 6 files changed, 164 insertions(+), 6 deletions(-) create mode 100644 fixtures/test_make_engineer.json diff --git a/access_controller/urls.py b/access_controller/urls.py index 7df57b3..2cab267 100644 --- a/access_controller/urls.py +++ b/access_controller/urls.py @@ -14,7 +14,6 @@ Including another URLconf 2. Add a URL to urlpatterns: path('blog/', include('blog.urls')) """ from django.contrib import admin -from django.contrib.auth import views from django.urls import path, include from main.views import main_page, profile_page, CustomRegistrationView, CustomLoginView, registration_error diff --git a/fixtures/test_make_engineer.json b/fixtures/test_make_engineer.json new file mode 100644 index 0000000..1154342 --- /dev/null +++ b/fixtures/test_make_engineer.json @@ -0,0 +1,85 @@ +[ + { + "model": "auth.user", + "pk": 1, + "fields": { + "password": "pbkdf2_sha256$216000$gHBBCr1jBELf$ZkEDW3IEd8Wij7u8vkv+0Eze32CS01bcaYWhcD9OIC4=", + "last_login": null, + "is_superuser": true, + "username": "admin@gmail.com", + "first_name": "", + "last_name": "", + "email": "admin@gmail.com", + "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": "123@test.ru", + "first_name": "", + "last_name": "", + "email": "123@test.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" + } + }, + { + "model": "auth.user", + "pk": 3, + "fields": { + "password": "pbkdf2_sha256$216000$5qLJgrm2Quq9$KDBNNymVZXkUx0HKBPFst2m83kLe0egPBnkW7KnkORU=", + "last_login": null, + "is_superuser": false, + "username": "customer@example.com", + "first_name": "", + "last_name": "", + "email": "customer@example.com", + "is_staff": false, + "is_active": true, + "date_joined": "2021-04-15T16:38:56.303Z", + "groups": [], + "user_permissions": [] + } + }, + { + "model": "main.userprofile", + "pk": 3, + "fields": { + "name": "UserForAccessTest", + "user": 3, + "role": "agent", + "custom_role_id": "360005209000" + } + } +] diff --git a/main/extra_func.py b/main/extra_func.py index c41625a..4494fc7 100644 --- a/main/extra_func.py +++ b/main/extra_func.py @@ -31,7 +31,7 @@ def update_role(user_profile: UserProfile, role: int, who_changes: User) -> None user_profile.custom_role_id = role user_profile.save() log(user_profile, who_changes.userprofile) - zendesk.admin.users.update(user) + zendesk.update_user(user) def make_engineer(user_profile: UserProfile, who_changes: User) -> None: diff --git a/main/templates/pages/adm_ruleset.html b/main/templates/pages/adm_ruleset.html index dc3cf54..cbbfc1b 100644 --- a/main/templates/pages/adm_ruleset.html +++ b/main/templates/pages/adm_ruleset.html @@ -17,9 +17,9 @@ - - + {# Для #} + {# Уведомлений #} {% endblock%} {% block content %}
diff --git a/main/tests.py b/main/tests.py index c06bc21..99d58cc 100644 --- a/main/tests.py +++ b/main/tests.py @@ -1,9 +1,10 @@ +from unittest.mock import patch from urllib.parse import urlparse from django.contrib.auth.models import User from django.core import mail from django.test import TestCase, Client -from django.urls import reverse +from django.urls import reverse, reverse_lazy from django.utils import translation import access_controller.settings as sets @@ -81,3 +82,69 @@ class RegistrationTestCase(TestCase): user = User.objects.get(email=self.zendesk_admin_email) self.assertEqual(user.userprofile.role, 'admin') self.assertTrue(user.has_perm('main.has_control_access')) + + +class MakeEngineerTestCase(TestCase): + fixtures = ['fixtures/test_make_engineer.json'] + + def setUp(self): + self.light_agent = '123@test.ru' + self.admin = 'admin@gmail.com' + self.engineer = 'customer@example.com' + self.client = Client() + self.client.force_login(User.objects.get(email=self.light_agent)) + self.admin_client = Client() + self.admin_client.force_login(User.objects.get(email=self.admin)) + + @patch('main.extra_func.zenpy') + def test_redirect(self, ZenpyMock): + user = User.objects.get(email=self.light_agent) + resp = self.client.post(reverse_lazy('work_become_engineer')) + self.assertRedirects(resp, reverse('work', args=[user.id])) + self.assertEqual(resp.status_code, 302) + + @patch('main.extra_func.zenpy') + def test_light_agent_make_engineer(self, ZenpyMock): + self.client.post(reverse_lazy('work_become_engineer')) + self.assertEqual(ZenpyMock.update_user.call_args[0][0].custom_role_id, sets.ZENDESK_ROLES['engineer']) + + @patch('main.extra_func.zenpy') + def test_admin_make_engineer(self, ZenpyMock): + self.admin_client.post(reverse_lazy('work_become_engineer')) + self.assertEqual(ZenpyMock.update_user.call_args[0][0].custom_role_id, sets.ZENDESK_ROLES['engineer']) + + @patch('main.extra_func.zenpy') + def test_engineer_make_engineer(self, ZenpyMock): + client = Client() + client.force_login(User.objects.get(email=self.engineer)) + client.post(reverse_lazy('work_become_engineer')) + self.assertEqual(ZenpyMock.update_user.call_args[0][0].custom_role_id, sets.ZENDESK_ROLES['engineer']) + + @patch('main.extra_func.zenpy') + def test_control_page_make_one(self, ZenpyMock): + self.admin_client.post( + reverse_lazy('control'), + data={'users': [User.objects.get(email=self.light_agent).userprofile.id], 'engineer': 'engineer'} + ) + call_list = ZenpyMock.update_user.call_args_list + mock_object = call_list[0][0][0] + self.assertEqual(len(call_list), 1) + self.assertEqual(mock_object.custom_role_id, sets.ZENDESK_ROLES['engineer']) + + @patch('main.extra_func.zenpy') + def test_control_page_make_many(self, ZenpyMock): + self.admin_client.post( + reverse_lazy('control'), + data={ + 'users': [ + User.objects.get(email=self.light_agent).userprofile.id, + User.objects.get(email=self.engineer).userprofile.id, + ], + 'engineer': 'engineer' + } + ) + call_list = ZenpyMock.update_user.call_args_list + mock_objects = list(call_list) + self.assertEqual(len(call_list), 2) + for obj in mock_objects: + self.assertEqual(obj[0][0].custom_role_id, sets.ZENDESK_ROLES['engineer']) diff --git a/main/zendesk_admin.py b/main/zendesk_admin.py index 8ecb877..2d12700 100644 --- a/main/zendesk_admin.py +++ b/main/zendesk_admin.py @@ -1,5 +1,4 @@ from typing import Optional, Dict - from zenpy import Zenpy from zenpy.lib.api_objects import User as ZenpyUser, Group as ZenpyGroup from zenpy.lib.exception import APIException @@ -22,6 +21,14 @@ class ZendeskAdmin: self.buffer_group_id: int = self.get_group(ZENDESK_GROUPS['buffer']).id self.solved_tickets_user_id: int = self.get_user(SOLVED_TICKETS_EMAIL).id + def update_user(self, user: ZenpyUser) -> bool: + """ + Функция сохраняет изменение пользователя в Zendesk. + + :param user: Пользователь с изменёнными данными + """ + self.admin.users.update(user) + def check_user(self, email: str) -> bool: """ Функция осуществляет проверку существования пользователя в Zendesk по email.