From 9f0ccf23e77f4fbdf55f95a7d4b5d0f7f0e61440 Mon Sep 17 00:00:00 2001 From: Dmitriy Andreev Date: Wed, 5 May 2021 20:43:25 +0300 Subject: [PATCH 1/9] Changes data.json in local --- data.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/data.json b/data.json index 97678f3..2afb1d9 100644 --- a/data.json +++ b/data.json @@ -23,7 +23,8 @@ "fields": { "name": "ZendeskAdmin", "user": 3, - "role": "admin" + "role": "admin", + "user_id": 1 } }, { From 8039e286ef318599db0f1cc9be6b5c6f2c809377 Mon Sep 17 00:00:00 2001 From: Andrew Smirnov Date: Thu, 20 May 2021 20:03:13 +0300 Subject: [PATCH 2/9] Fix tests.py, add migration, fix pylint --- .../0018_alter_unassignedticket_ticket_id.py | 18 +++++++++++++ main/tests.py | 27 ++++++++++++------- 2 files changed, 35 insertions(+), 10 deletions(-) create mode 100644 main/migrations/0018_alter_unassignedticket_ticket_id.py diff --git a/main/migrations/0018_alter_unassignedticket_ticket_id.py b/main/migrations/0018_alter_unassignedticket_ticket_id.py new file mode 100644 index 0000000..7899c3c --- /dev/null +++ b/main/migrations/0018_alter_unassignedticket_ticket_id.py @@ -0,0 +1,18 @@ +# Generated by Django 3.2.3 on 2021-05-20 17:00 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('main', '0017_auto_20210408_1943'), + ] + + operations = [ + migrations.AlterField( + model_name='unassignedticket', + name='ticket_id', + field=models.IntegerField(help_text='Номер тикета, для которого сняли ответственного'), + ), + ] diff --git a/main/tests.py b/main/tests.py index 5365782..7946c01 100644 --- a/main/tests.py +++ b/main/tests.py @@ -30,11 +30,11 @@ class UsersBaseTestCase(TestCase): self.admin = 'admin@gmail.com' self.engineer = 'customer@example.com' self.agent_client = Client() - self.agent_client.force_login(User.objects.get(email=self.light_agent)) + self.agent_client.force_login(get_user_model().objects.get(email=self.light_agent)) self.admin_client = Client() - self.admin_client.force_login(User.objects.get(email=self.admin)) + self.admin_client.force_login(get_user_model().objects.get(email=self.admin)) self.engineer_client = Client() - self.engineer_client.force_login(User.objects.get(email=self.engineer)) + self.engineer_client.force_login(get_user_model().objects.get(email=self.engineer)) class RegistrationTestCase(TestCase): @@ -252,7 +252,10 @@ class MakeLightAgentTestCase(UsersBaseTestCase): def test_control_page_make_light_agent_one(self, zenpy_mock, _user_tickets_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] @@ -330,7 +333,12 @@ class PasswordResetTestCase(UsersBaseTestCase): Функция корректности отработки неверно введенного 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) @@ -503,11 +511,11 @@ class GetTicketsTestCase(UsersBaseTestCase): @patch('main.views.zenpy') @patch('main.views.get_tickets_list_for_group') - def test_take_zero_tickets(self, TicketsMock, zenpy_mock): + def test_take_zero_tickets(self, tickets_mock, zenpy_mock): """ Функция проверки попытки назначения нуля тикета на engineer. """ - TicketsMock.return_value = [Mock()] * 3 + tickets_mock.return_value = [Mock()] * 3 zenpy_mock.get_user.return_value = Mock(role='agent', custom_role_id=sets.ZENDESK_ROLES['engineer']) self.engineer_client.post(reverse('work_get_tickets'), data={'count_tickets': 0}) tickets = zenpy_mock.update_tickets.call_args[0][0] @@ -596,9 +604,8 @@ class LoggingTestCase(UsersBaseTestCase): @staticmethod def get_file_output(): - file = open('logs/logs.csv', 'r') - file_output = file.readlines()[-1] - file.close() + with open('logs/logs.csv', 'r') as file: + file_output = file.readlines()[-1] return file_output def test_engineer_with_admin(self): From 724d246b6befdce8d438df1f0fd659408d6f2c17 Mon Sep 17 00:00:00 2001 From: Iurii Tatishchev Date: Tue, 25 May 2021 09:44:02 -0700 Subject: [PATCH 3/9] Remove venv from git --- .../site-packages/enchant/tokenize/ru.py | 185 ------------------ 1 file changed, 185 deletions(-) delete mode 100644 venv/lib/python3.6/site-packages/enchant/tokenize/ru.py diff --git a/venv/lib/python3.6/site-packages/enchant/tokenize/ru.py b/venv/lib/python3.6/site-packages/enchant/tokenize/ru.py deleted file mode 100644 index 7e15379..0000000 --- a/venv/lib/python3.6/site-packages/enchant/tokenize/ru.py +++ /dev/null @@ -1,185 +0,0 @@ -# pyenchant -# -# Copyright (C) 2004-2008, Ryan Kelly -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the -# Free Software Foundation, Inc., 59 Temple Place - Suite 330, -# Boston, MA 02111-1307, USA. -# -# In addition, as a special exception, you are -# given permission to link the code of this program with -# non-LGPL Spelling Provider libraries (eg: a MSFT Office -# spell checker backend) and distribute linked combinations including -# the two. You must obey the GNU Lesser General Public License in all -# respects for all of the code used other than said providers. If you modify -# this file, you may extend this exception to your version of the -# file, but you are not obligated to do so. If you do not wish to -# do so, delete this exception statement from your version. -# -""" - - enchant.tokenize.en: Tokenizer for the English language - - This module implements a PyEnchant text tokenizer for the English - language, based on very simple rules. - -""" - -import unicodedata - -import enchant.tokenize - - -class tokenize(enchant.tokenize.tokenize): # noqa: N801 - """Iterator splitting text into words, reporting position. - - This iterator takes a text string as input, and yields tuples - representing each distinct word found in the text. The tuples - take the form: - - (,) - - Where is the word string found and is the position - of the start of the word within the text. - - The optional argument may be used to specify a - list of additional characters that can form part of a word. - By default, this list contains only the apostrophe ('). Note that - these characters cannot appear at the start or end of a word. - """ - - _DOC_ERRORS = ["pos", "pos"] - - def __init__(self, text, valid_chars=None): - self._valid_chars = valid_chars - self._text = text - self._offset = 0 - # Select proper implementation of self._consume_alpha. - # 'text' isn't necessarily a string (it could be e.g. a mutable array) - # so we can't use isinstance(text, str) to detect unicode. - # Instead we typetest the first character of the text. - # If there's no characters then it doesn't matter what implementation - # we use since it won't be called anyway. - try: - char1 = text[0] - except IndexError: - self._initialize_for_binary() - else: - if isinstance(char1, str): - self._initialize_for_unicode() - else: - self._initialize_for_binary() - - def _initialize_for_binary(self): - self._consume_alpha = self._consume_alpha_b - if self._valid_chars is None: - self._valid_chars = ("'",) - - def _initialize_for_unicode(self): - self._consume_alpha = self._consume_alpha_u - if self._valid_chars is None: - # XXX TODO: this doesn't seem to work correctly with the - # MySpell provider, disabling for now. - # Allow unicode typographic apostrophe - # self._valid_chars = (u"'",u"\u2019") - self._valid_chars = ("'",) - - def _consume_alpha_b(self, text, offset): - """Consume an alphabetic character from the given bytestring. - - Given a bytestring and the current offset, this method returns - the number of characters occupied by the next alphabetic character - in the string. Non-ASCII bytes are interpreted as utf-8 and can - result in multiple characters being consumed. - """ - assert offset < len(text) - if text[offset].isalpha(): - return 1 - elif text[offset] >= "\x80": - return self._consume_alpha_utf8(text, offset) - return 0 - - def _consume_alpha_utf8(self, text, offset): - """Consume a sequence of utf8 bytes forming an alphabetic character.""" - incr = 2 - u = "" - while not u and incr <= 4: - try: - try: - # In the common case this will be a string - u = text[offset : offset + incr].decode("utf8") - except AttributeError: - # Looks like it was e.g. a mutable char array. - try: - s = text[offset : offset + incr].tostring() - except AttributeError: - s = "".join([c for c in text[offset : offset + incr]]) - u = s.decode("utf8") - except UnicodeDecodeError: - incr += 1 - if not u: - return 0 - if u.isalpha(): - return incr - if unicodedata.category(u)[0] == "M": - return incr - return 0 - - def _consume_alpha_u(self, text, offset): - """Consume an alphabetic character from the given unicode string. - - Given a unicode string and the current offset, this method returns - the number of characters occupied by the next alphabetic character - in the string. Trailing combining characters are consumed as a - single letter. - """ - assert offset < len(text) - incr = 0 - if text[offset].isalpha(): - incr = 1 - while offset + incr < len(text): - if unicodedata.category(text[offset + incr])[0] != "M": - break - incr += 1 - return incr - - def next(self): - text = self._text - offset = self._offset - while offset < len(text): - # Find start of next word (must be alpha) - while offset < len(text): - incr = self._consume_alpha(text, offset) - if incr: - break - offset += 1 - cur_pos = offset - # Find end of word using, allowing valid_chars - while offset < len(text): - incr = self._consume_alpha(text, offset) - if not incr: - if text[offset] in self._valid_chars: - incr = 1 - else: - break - offset += incr - # Return if word isn't empty - if cur_pos != offset: - # Make sure word doesn't end with a valid_char - while text[offset - 1] in self._valid_chars: - offset = offset - 1 - self._offset = offset - return (text[cur_pos:offset], cur_pos) - self._offset = offset - raise StopIteration() From 33421ca11229c95a42ee86b7c15f516bf8d1aeaa Mon Sep 17 00:00:00 2001 From: Sokurov Idar Date: Tue, 25 May 2021 21:45:28 +0300 Subject: [PATCH 4/9] del inint.py --- __init__.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 __init__.py diff --git a/__init__.py b/__init__.py deleted file mode 100644 index e69de29..0000000 From 614b82c24d897e4ea25f5fa0f82f609ddf5e93a5 Mon Sep 17 00:00:00 2001 From: Iurii Tatishchev Date: Tue, 25 May 2021 12:22:43 -0700 Subject: [PATCH 5/9] Update README.md pylint section --- README.md | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index b3376cf..1438361 100644 --- a/README.md +++ b/README.md @@ -149,22 +149,25 @@ docker run -d -p 8000:8000 \ Пример полной конфигурации можно найти в [.env.example](.env.example). Почту и токен админа ZenDesk взять у руководителя (если вы не админ). ## Для проверки pylint используем: -pylint --django-settings-module=access_controller.access_controller.settings ../access_controller (каталог, где лежит проект) +```bash +pylint --django-settings-module=access_controller.settings main +``` ## Для приведения файлов к стандарту PEP8 используем: +```bash autopep8 --in-place filename +``` ##Для проверки орфографии: -cd docs +```bash +(cd docs && make spelling) +``` -(set -a && source ../.env && make spelling) ##Для обновления документации: +```bash m2r README.md - -cd docs - -(set -a && source ../.env && make html) - +(cd docs && make html) +``` ## Read more - Zenpy: [http://docs.facetoe.com.au](http://docs.facetoe.com.au) From bdd5a68b268328ea013a77225f733eb85990ed4b Mon Sep 17 00:00:00 2001 From: Dmitriy Andreev Date: Wed, 26 May 2021 15:34:28 +0300 Subject: [PATCH 6/9] profile look fix --- main/templates/pages/profile.html | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/main/templates/pages/profile.html b/main/templates/pages/profile.html index 4b7016a..2f628f8 100644 --- a/main/templates/pages/profile.html +++ b/main/templates/pages/profile.html @@ -23,7 +23,7 @@ {% block content %}
-
+

Имя пользователя

{{ profile.name }}
@@ -44,7 +46,7 @@ {% elif profile.custom_role_id == ZENDESK_ROLES.light_agent %}
light_agent
{% else %} -
None
+
Без роли
{% endif %}
@@ -52,7 +54,7 @@
{% endblock %} From 72030040b842b47f77ef13329038f0cafb1b4f75 Mon Sep 17 00:00:00 2001 From: Dmitriy Andreev Date: Wed, 26 May 2021 17:05:48 +0300 Subject: [PATCH 7/9] Fix looking of profile, work and control pages --- main/templates/pages/adm_ruleset.html | 12 +-- main/templates/pages/profile.html | 4 +- main/templates/pages/work.html | 123 ++++++++++++++------------ static/main/js/control.js | 4 +- 4 files changed, 74 insertions(+), 69 deletions(-) diff --git a/main/templates/pages/adm_ruleset.html b/main/templates/pages/adm_ruleset.html index cbbfc1b..39caf41 100644 --- a/main/templates/pages/adm_ruleset.html +++ b/main/templates/pages/adm_ruleset.html @@ -39,10 +39,10 @@
-
Список сотрудников
+

Список сотрудников

{% block table %} - +
+ From 8b3f8b8b8748504006f38b1abc3f7619ee33d8e1 Mon Sep 17 00:00:00 2001 From: Dmitriy Andreev Date: Wed, 26 May 2021 17:47:32 +0300 Subject: [PATCH 8/9] Page design became better for user. Changes in profile, work, control and statistic pages. --- main/templates/base/base.html | 2 ++ main/templates/pages/statistic.html | 26 +++++++++++++------------- 2 files changed, 15 insertions(+), 13 deletions(-) diff --git a/main/templates/base/base.html b/main/templates/base/base.html index 166195d..e82af52 100644 --- a/main/templates/base/base.html +++ b/main/templates/base/base.html @@ -19,6 +19,8 @@ user-select: none; } + + @media (min-width: 768px) { .bd-placeholder-img-lg { font-size: 3.5rem; diff --git a/main/templates/pages/statistic.html b/main/templates/pages/statistic.html index b467250..82b714a 100644 --- a/main/templates/pages/statistic.html +++ b/main/templates/pages/statistic.html @@ -7,21 +7,21 @@ {% block heading %} Страницы просмотра статистики{% endblock %} {% block content%} -
+
{% csrf_token %}
-
- {{ form.email.label }} +
+

{{ form.email.label }}

{{ form.email }}
-
- {{ form.interval.label }} +
+

{{ form.interval.label }}

{% for radio in form.interval%} @@ -33,8 +33,8 @@
-
- {{ form.display_format.label }} +
+

{{ form.display_format.label }}

{% for radio in form.display_format%} @@ -46,8 +46,8 @@
-
- {{ form.range_start.label}} +
+

{{ form.range_start.label}}

@@ -56,8 +56,8 @@
-
- {{ form.range_end.label}} +
+

{{ form.range_end.label}}

@@ -65,9 +65,9 @@
-
+
- +
From e595156f56753ee0e3f3c09d85ba1f59d431b240 Mon Sep 17 00:00:00 2001 From: Iurii Tatishchev Date: Wed, 26 May 2021 09:10:26 -0700 Subject: [PATCH 9/9] Change custom role ids to BigInt for postgres compatibility. --- access_controller/settings.py | 4 +++- main/models.py | 6 +++--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/access_controller/settings.py b/access_controller/settings.py index 55af7a5..056de17 100644 --- a/access_controller/settings.py +++ b/access_controller/settings.py @@ -147,7 +147,6 @@ LOGIN_REDIRECT_URL = '/' LOGOUT_REDIRECT_URL = '/' - # Название_приложения.Название_файла.Название_класса_обработчика AUTHENTICATION_BACKENDS = [ 'access_controller.auth.EmailAuthBackend', @@ -185,3 +184,6 @@ ACTRL_ZENDESK_SUBDOMAIN = os.getenv('ACTRL_ZENDESK_SUBDOMAIN') or os.getenv('ZD_ ACTRL_API_EMAIL = os.getenv('ACTRL_API_EMAIL') or os.getenv('ACCESS_CONTROLLER_API_EMAIL') ACTRL_API_TOKEN = os.getenv('ACTRL_API_TOKEN') or os.getenv('ACCESS_CONTROLLER_API_TOKEN') ACTRL_API_PASSWORD = os.getenv('ACTRL_API_PASSWORD') or os.getenv('ACCESS_CONTROLLER_API_PASSWORD') + + +DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField' diff --git a/main/models.py b/main/models.py index c934ab1..828fce2 100644 --- a/main/models.py +++ b/main/models.py @@ -24,7 +24,7 @@ class UserProfile(models.Model): user = models.OneToOneField(to=get_user_model(), on_delete=models.CASCADE, help_text='Пользователь') role = models.CharField(default='None', max_length=100, help_text='Глобальное имя роли пользователя') - custom_role_id = models.IntegerField(default=0, help_text='Код роли пользователя') + custom_role_id = models.BigIntegerField(default=0, help_text='Код роли пользователя') image = models.URLField(null=True, blank=True, help_text='Аватарка') name = models.CharField(default='None', max_length=100, help_text='Имя пользователя на нашем сайте') @@ -75,8 +75,8 @@ class RoleChangeLogs(models.Model): """ user = models.ForeignKey(to=get_user_model(), on_delete=models.CASCADE, help_text='Пользователь, которому присвоили другую роль') - old_role = models.IntegerField(default=0, help_text='Старая роль') - new_role = models.IntegerField(default=0, help_text='Присвоенная роль') + old_role = models.BigIntegerField(default=0, help_text='Старая роль') + new_role = models.BigIntegerField(default=0, help_text='Присвоенная роль') change_time = models.DateTimeField(default=timezone.now, help_text='Дата и время изменения роли') changed_by = models.ForeignKey(to=get_user_model(), on_delete=models.CASCADE, related_name='changed_by', help_text='Кем была изменена роль')
@@ -71,7 +71,7 @@
-
Инженеров:
+
Инженеров:
{{ engineers }} @@ -79,7 +79,7 @@
-
Легких агентов:
+
Легких агентов:
{{ light_agents }} @@ -93,11 +93,11 @@ {% block buttons %}
- -
diff --git a/main/templates/pages/profile.html b/main/templates/pages/profile.html index 2f628f8..d5f95b3 100644 --- a/main/templates/pages/profile.html +++ b/main/templates/pages/profile.html @@ -32,7 +32,7 @@ >
@@ -54,7 +54,7 @@
{% endblock %} diff --git a/main/templates/pages/work.html b/main/templates/pages/work.html index bd46341..8144b1b 100644 --- a/main/templates/pages/work.html +++ b/main/templates/pages/work.html @@ -16,66 +16,73 @@ {% endblock %} {% block content %} -
-
-

Свободных Мест: {{ licences_remaining }}

-
+

Свободных Мест: {{ licences_remaining }}

-
-
-
Список сотрудников с правами инженера
- - - - - - - {% for engineer in engineers %} - - - - - {% endfor %} - -
EmailName
{{ engineer.email }}{{ engineer.name }}
-
-
-
-
-
-
-
инженеров:
-
-
- {{ engineers|length }} -
-
-
-
легких агентов:
-
-
- {{ agents|length }} -
- -
-
-
- -
-
- {% csrf_token %} - {{ get_tickets_form.count_tickets }} - -
-
- {% for message in messages %} - - {% endfor %} -
+
+
+

Список сотрудников с правами инженера

+ + + + + + + {% for engineer in engineers %} + + + + + {% endfor %} + +
EmailName
{{ engineer.email }}{{ engineer.name }}
+
+
+
+
+
+
инженеров:
+
+
+ {{ engineers|length }} +
+
+
+
легких агентов:
+
+
+ {{ agents|length }} +
+ +
+
+
+
+ + + +
+
+ +
+
+ +
+
+
+
+ +{% for message in messages %} + +{% endfor %} {% endblock %} diff --git a/static/main/js/control.js b/static/main/js/control.js index 6dd9172..c7a9d06 100644 --- a/static/main/js/control.js +++ b/static/main/js/control.js @@ -21,9 +21,7 @@ class ModelUserTableRow extends React.Component { name="users" /> -
- {this.props.user.name} - {this.props.user.name} {this.props.user.user.email} {this.props.user.zendesk_role}