From 8e0610840d5191175b47979ef0e622cd799c90b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=A1=D1=82=D0=B5=D0=BF=D0=B0=D0=BD=D0=B5=D0=BD=D0=BA?= =?UTF-8?q?=D0=BE=20=D0=9E=D0=BB=D1=8C=D0=B3=D0=B0?= Date: Tue, 27 Apr 2021 19:41:47 +0300 Subject: [PATCH] Pylint 7.5 --- README.md | 5 ++- main/apps.py | 6 +++ main/extra_func.py | 83 +++++++++++++++++++++++++++-------------- main/forms.py | 3 +- main/models.py | 39 +++++++++++++------ main/views.py | 26 +++++++++---- requirements/common.txt | 1 + 7 files changed, 113 insertions(+), 50 deletions(-) diff --git a/README.md b/README.md index 603f229..97d63bb 100644 --- a/README.md +++ b/README.md @@ -148,7 +148,10 @@ docker run -d -p 8000:8000 \ Пример полной конфигурации можно найти в [.env.example](.env.example). Почту и токен админа ZenDesk взять у руководителя (если вы не админ). ## Для проверки pylint используем: -pylint --load-plugins pylint_django ../access_controller +pylint --load-plugins pylint_django --disable=E5110,C0415 ../access_controller + +## Для приведения файлов к стандарту PEP8 используем: +autopep8 --in-place ## Read more - Zenpy: [http://docs.facetoe.com.au](http://docs.facetoe.com.au) diff --git a/main/apps.py b/main/apps.py index 833bff6..b521b37 100644 --- a/main/apps.py +++ b/main/apps.py @@ -1,5 +1,11 @@ +""" +Стандартный файл Django конфигурации приложения. +""" from django.apps import AppConfig class MainConfig(AppConfig): + """ + Старт приложения + """ name = 'main' diff --git a/main/extra_func.py b/main/extra_func.py index acaabb5..2e759b2 100644 --- a/main/extra_func.py +++ b/main/extra_func.py @@ -38,7 +38,8 @@ def make_engineer(user_profile: UserProfile, who_changes: User) -> None: Функция устанавливает пользователю роль инженера. :param user_profile: Профиль пользователя - :return: Вызов функции **update_role** с параметрами: профиль пользователя, роль "engineer" + :return: Вызов функции **update_role** с параметрами: + профиль пользователя, роль "engineer" """ update_role(user_profile, ROLES['engineer']) @@ -48,7 +49,8 @@ def make_light_agent(user_profile: UserProfile) -> None: Функция устанавливает пользователю роль легкого агента. :param user_profile: Профиль пользователя - :return: Вызов функции **update_role** с параметрами: профиль пользователя, роль "light_agent" + :return: Вызов функции **update_role** с параметрами: + профиль пользователя, роль "light_agent" """ tickets = get_tickets_list(user_profile.user.email) ticket: ZenpyTicket @@ -56,7 +58,8 @@ def make_light_agent(user_profile: UserProfile) -> None: UnassignedTicket.objects.create( assignee=user_profile.user, ticket_id=ticket.id, - status=UnassignedTicketStatus.SOLVED if ticket.status == 'solved' else UnassignedTicketStatus.UNASSIGNED + status=UnassignedTicketStatus.SOLVED if ticket.status == 'solved' + else UnassignedTicketStatus.UNASSIGNED ) if ticket.status == 'solved': ticket.assignee_id = zenpy.solved_tickets_user_id @@ -79,7 +82,8 @@ def make_light_agent(user_profile: UserProfile) -> None: def get_users_list() -> list: """ - Функция **get_users_list** возвращает список пользователей Zendesk, относящихся к организации SYSTEM. + Функция **get_users_list** возвращает список + пользователей Zendesk, относящихся к организации SYSTEM. """ zendesk = zenpy @@ -101,7 +105,8 @@ def update_profile(user_profile: UserProfile) -> None: Функция обновляет профиль пользователя в соответствии с текущим в Zendesk. :param user_profile: Профиль пользователя - :return: Обновленный, в соответствие с текущими данными в Zendesk, профиль пользователя + :return: Обновленный, в соответствие с текущими данными + в Zendesk, профиль пользователя """ user = zenpy.get_user(user_profile.user.email) user_profile.name = user.name @@ -135,7 +140,8 @@ def check_user_auth(email: str, password: str) -> bool: """ Функция проверяет, верны ли входные данные. - :raise: :class:`APIException`: исключение, вызываемое если пользователь не аутентифицирован + :raise: :class:`APIException`: исключение, + вызываемое если пользователь не аутентифицирован """ creds = { 'email': email, @@ -207,10 +213,12 @@ def daterange(start_date: timedelta, end_date: timedelta) -> list: return dates -def get_timedelta(log: RoleChangeLogs, time: timedelta=None) -> timedelta: +def get_timedelta(log: RoleChangeLogs, time: timedelta = None) -> timedelta: """ - Функция возвращает объект класса timedelta, который хранит промежуток времени от начала суток до момента, - который находится в log (объект класса RoleChangeLogs) или в time(datetime.time), если введён. + Функция возвращает объект класса timedelta, + который хранит промежуток времени от начала суток до момента, + который находится в log (объект класса RoleChangeLogs) + или в time(datetime.time), если введён. :param log: Лог :param time: Время @@ -278,7 +286,9 @@ class StatisticData: """ Функция возвращает статистику работы пользователя. - :return: Словарь statistic с применением формата отображения и интервала работы(если они есть). None, если были ошибки при создании. + :return: Словарь statistic с применением формата отображения + и интервала работы(если они есть). + None, если были ошибки при создании. """ if self.is_valid_statistic(): stat = self.statistic @@ -369,9 +379,12 @@ class StatisticData: if self.interval == 'months': # Переделываем ключи под формат('начало_месяца - конец_месяца') for key, value in stat.items(): - current_month_start = max(self.start_date, date(year=key.year, month=key.month, day=1)) - current_month_end = min(self.end_date, last_day_of_month(date(year=key.year, month=key.month, day=1))) - index = ' - '.join([str(current_month_start), str(current_month_end)]) + current_month_start = max(self.start_date, date( + year=key.year, month=key.month, day=1)) + current_month_end = min(self.end_date, last_day_of_month( + date(year=key.year, month=key.month, day=1))) + index = ' - '.join([str(current_month_start), + str(current_month_end)]) if new_stat.get(index): new_stat[index] += value else: @@ -392,16 +405,20 @@ class StatisticData: def _init_data(self) -> None: """ - Функция возвращает логи в диапазоне дат start_date - end_date для пользователя с указанным email. + Функция возвращает логи в диапазоне дат + start_date - end_date для пользователя с указанным email. - :return: Данные о смене статусов пользователя. Если пользователь не найден или интервал времени некорректен - ошибку. + :return: Данные о смене статусов пользователя. + Если пользователь не найден или интервал времени некорректен - ошибку. """ if not self.check_time(): - self.errors += ['Конец диапазона должен быть позже начала диапазона и раньше текущего времени'] + self.errors += [ + 'Конец диапазона должен быть позже начала диапазона и раньше текущего времени'] return try: self.data = RoleChangeLogs.objects.filter( - change_time__range=[self.start_date, self.end_date + timedelta(days=1)], + change_time__range=[self.start_date, + self.end_date + timedelta(days=1)], user=User.objects.get(email=self.email), ).order_by('change_time') except User.DoesNotExist: @@ -409,7 +426,8 @@ class StatisticData: def _init_statistic(self) -> None: """ - Функция заполняет словарь, в котором ключ - дата, значение - кол-во проработанных в этот день секунд. + Функция заполняет словарь, в котором ключ - дата, + значение - кол-во проработанных в этот день секунд. :return: Статистика работы пользователя (statistic) """ @@ -439,11 +457,14 @@ class StatisticData: if current_log.change_time.date() != next_log.change_time.date(): self.statistic[current_log.change_time.date()] += ( timedelta(days=1) - get_timedelta(current_log)).total_seconds() - self.statistic[next_log.change_time.date()] += get_timedelta(next_log).total_seconds() - self.fill_daterange(current_log.change_time.date() + timedelta(days=1), next_log.change_time.date()) + self.statistic[next_log.change_time.date( + )] += get_timedelta(next_log).total_seconds() + self.fill_daterange(current_log.change_time.date( + ) + timedelta(days=1), next_log.change_time.date()) else: elapsed_time = next_log.change_time - current_log.change_time - self.statistic[current_log.change_time.date()] += elapsed_time.total_seconds() + self.statistic[current_log.change_time.date( + )] += elapsed_time.total_seconds() def post_engineer_logic(self, last_log: RoleChangeLogs) -> None: """ @@ -451,16 +472,19 @@ class StatisticData: :param last_log: Последний лог """ - self.fill_daterange(last_log.change_time.date() + timedelta(days=1), self.end_date + timedelta(days=1)) + 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(): self.statistic[last_log.change_time.date()] += ( - get_timedelta(None, timezone.now().time()) - get_timedelta(last_log) + get_timedelta(None, timezone.now().time()) - + get_timedelta(last_log) ).total_seconds() else: self.statistic[last_log.change_time.date()] += ( timedelta(days=1) - get_timedelta(last_log)).total_seconds() if self.end_date == timezone.now().date(): - self.statistic[self.end_date] = get_timedelta(None, timezone.now().time()).total_seconds() + self.statistic[self.end_date] = get_timedelta( + None, timezone.now().time()).total_seconds() def prev_engineer_logic(self, first_log: RoleChangeLogs) -> None: """ @@ -470,7 +494,8 @@ class StatisticData: """ self.fill_daterange(max(User.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() + 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) -> None: """ @@ -488,7 +513,8 @@ class StatisticData: Функция осуществляет обновление всех дней. """ self.statistic.clear() - self.fill_daterange(self.start_date, self.end_date + timedelta(days=1), 0) + self.fill_daterange( + self.start_date, self.end_date + timedelta(days=1), 0) class DatabaseHandler(logging.Handler): @@ -571,9 +597,10 @@ def log(user: User, admin: int = 0) -> None: def set_session_params_for_work_page(request: WSGIRequest, count: int = None, is_confirm: bool = True) -> \ - Union[HttpResponsePermanentRedirect, HttpResponseRedirect]: + Union[HttpResponsePermanentRedirect, HttpResponseRedirect]: """ - Функция для страницы получения прав, устанавливает данные сессии о успешности запроса и количестве назначенных тикетов. + Функция для страницы получения прав, устанавливает данные сессии + о успешности запроса и количестве назначенных тикетов. :param request: Получение данных с рабочей страницы пользователя :param count: Количество запрошенных тикетов diff --git a/main/forms.py b/main/forms.py index 0f6b44c..36d2e88 100644 --- a/main/forms.py +++ b/main/forms.py @@ -66,8 +66,7 @@ class CustomAuthenticationForm(AuthenticationForm): error_messages = { 'invalid_login': "Пожалуйста, введите правильные электронную почту и пароль. Оба поля " - "могут быть чувствительны к регистру." - , + "могут быть чувствительны к регистру.", 'inactive': "Аккаунт не активен.", } diff --git a/main/models.py b/main/models.py index 0d49acf..c955636 100644 --- a/main/models.py +++ b/main/models.py @@ -19,11 +19,15 @@ class UserProfile(models.Model): ('has_control_access', 'Can view admin page'), ) - user = models.OneToOneField(to=User, 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='Код роли пользователя') + user = models.OneToOneField( + to=User, 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='Код роли пользователя') image = models.URLField(null=True, blank=True, help_text='Аватарка') - name = models.CharField(default='None', max_length=100, help_text='Имя пользователя на нашем сайте') + name = models.CharField(default='None', max_length=100, + help_text='Имя пользователя на нашем сайте') @property def zendesk_role(self): @@ -49,12 +53,16 @@ class RoleChangeLogs(models.Model): """ Модель для логирования изменений ролей пользователя. """ - user = models.ForeignKey(to=User, on_delete=models.CASCADE, + user = models.ForeignKey(to=User, + on_delete=models.CASCADE, help_text='Пользователь, которому присвоили другую роль') old_role = models.IntegerField(default=0, help_text='Старая роль') new_role = models.IntegerField(default=0, help_text='Присвоенная роль') - change_time = models.DateTimeField(default=timezone.now, help_text='Дата и время изменения роли') - changed_by = models.ForeignKey(to=User, on_delete=models.CASCADE, related_name='changed_by', + change_time = models.DateTimeField( + default=timezone.now, help_text='Дата и время изменения роли') + changed_by = models.ForeignKey(to=User, + on_delete=models.CASCADE, + related_name='changed_by', help_text='Кем была изменена роль') @@ -64,13 +72,15 @@ class UnassignedTicketStatus(models.IntegerChoices): :param UNASSIGNED: Снят с пользователя, перенесён в буферную группу :param RESTORED: Авторство восстановлено - :param NOT_FOUND: Пока нас не было, тикет испарился из буферной группы. Дополнительные действия не требуются + :param NOT_FOUND: Пока нас не было, тикет испарился из буферной группы. + Дополнительные действия не требуются :param CLOSED: Тикет уже был закрыт. Дополнительные действия не требуются :param SOLVED: Тикет решён. Записан на пользователя с почтой SOLVED_TICKETS_EMAIL """ UNASSIGNED = 0, 'Снят с пользователя, перенесён в буферную группу' RESTORED = 1, 'Авторство восстановлено' - NOT_FOUND = 2, 'Пока нас не было, тикет испарился из буферной группы. Дополнительные действия не требуются' + NOT_FOUND = 2, 'Пока нас не было, тикет испарился из ' \ + 'буферной группы. Дополнительные действия не требуются' CLOSED = 3, 'Тикет уже был закрыт. Дополнительные действия не требуются' SOLVED = 4, 'Тикет решён. Записан на пользователя с почтой SOLVED_TICKETS_EMAIL' @@ -79,6 +89,11 @@ class UnassignedTicket(models.Model): """ Модель не распределенного тикета. """ - assignee = models.ForeignKey(to=User, on_delete=models.CASCADE, related_name='tickets', help_text='Пользователь, с которого снят тикет') - ticket_id = models.IntegerField(help_text='Номер тикера, для которого сняли ответственного') - status = models.IntegerField(choices=UnassignedTicketStatus.choices, default=UnassignedTicketStatus.UNASSIGNED, help_text='Статус тикета') + assignee = models.ForeignKey(to=User, on_delete=models.CASCADE, + related_name='tickets', + help_text='Пользователь, с которого снят тикет') + ticket_id = models.IntegerField( + help_text='Номер тикера, для которого сняли ответственного') + status = models.IntegerField(choices=UnassignedTicketStatus.choices, + default=UnassignedTicketStatus.UNASSIGNED, + help_text='Статус тикета') diff --git a/main/views.py b/main/views.py index 2059a17..68ea8d1 100644 --- a/main/views.py +++ b/main/views.py @@ -1,3 +1,7 @@ +""" +Основной функционал приложения. +""" + from smtplib import SMTPException from typing import Dict, Any @@ -117,7 +121,8 @@ class CustomRegistrationView(RegistrationView): @staticmethod def set_permission(user: User) -> None: """ - Функция дает разрешение на просмотр страница администратора, если пользователь имеет роль admin. + Функция дает разрешение на просмотр страница администратора, + если пользователь имеет роль admin. :param user: авторизованный пользователь (получает разрешение, имея роль "admin") """ @@ -131,7 +136,8 @@ class CustomRegistrationView(RegistrationView): def get_success_url(self, user: User = None) -> Dict: """ - Функция возвращает url-адрес страницы, куда нужно перейти после успешной/не успешной регистрации. + Функция возвращает url-адрес страницы, куда нужно перейти после + успешной/не успешной регистрации. Используется самой django-registration. :param user: пользователь, пытающийся зарегистрироваться @@ -172,11 +178,13 @@ def profile_page(request: WSGIRequest) -> HttpResponse: @login_required() def work_page(request: WSGIRequest, id: int) -> HttpResponse: """ - Функция отображения страницы "Управления правами" для текущего пользователя (login_required). + Функция отображения страницы "Управления правами" + для текущего пользователя (login_required). :param request: объект пользователя :param id: id пользователя, используется для динамической адресации - :return: адресация на страницу "Управления правами" (либо на страницу "Авторизации", если id и user.id не совпадают + :return: адресация на страницу "Управления правами" + (либо на страницу "Авторизации", если id и user.id не совпадают) """ users = get_users_list() if request.user.id == id: @@ -212,7 +220,8 @@ def work_page(request: WSGIRequest, id: int) -> HttpResponse: @login_required() def work_hand_over(request: WSGIRequest) -> HttpResponseRedirect: """ - Функция позволяет текущему пользователю сдать права, а именно сменить в Zendesk роль с "engineer" на "light_agent" + Функция позволяет текущему пользователю сдать права, + а именно сменить в Zendesk роль с "engineer" на "light_agent" :param request: данные текущего пользователя (login_required) :return: перезагрузка текущей страницы после выполнения смены роли @@ -224,7 +233,9 @@ def work_hand_over(request: WSGIRequest) -> HttpResponseRedirect: @login_required() def work_become_engineer(request: WSGIRequest) -> HttpResponseRedirect: """ - Функция позволяет текущему пользователю получить права, а именно сменить в Zendesk роль с "light_agent" на "engineer" + Функция позволяет текущему пользователю получить права, + а именно сменить в Zendesk роль с "light_agent" на + "engineer" :param request: данные текущего пользователя (login_required) :return: перезагрузка текущей страницы после выполнения смены роли @@ -371,7 +382,8 @@ def statistic_page(request: WSGIRequest) -> HttpResponse: """ Функция отображения страницы статистики (для "superuser"). - :param request: данные о пользователе: email, время и интервал работы. Данные получаем через forms.StatisticForm + :param request: данные о пользователе: email, время и интервал работы. + Данные получаем через forms.StatisticForm :return: адресация на страницу статистики """ diff --git a/requirements/common.txt b/requirements/common.txt index 4417add..58befa7 100644 --- a/requirements/common.txt +++ b/requirements/common.txt @@ -17,3 +17,4 @@ sphinxcontrib-spelling==7.1.0 m2r == 0.2.1 pylint == 2.8.2 pylint-django == 2.4.4 +autopep8 = 1.5.6