From 674df0e66b1f5139c9058596bbf7fbc4bbe0206f Mon Sep 17 00:00:00 2001 From: Andrew Smirnov Date: Thu, 11 Mar 2021 20:28:04 +0300 Subject: [PATCH 1/7] Add model for tracking unassigned tickets --- main/migrations/0012_auto_20210311_2027.py | 29 ++++++++++++++++++++++ main/models.py | 13 +++++++++- 2 files changed, 41 insertions(+), 1 deletion(-) create mode 100644 main/migrations/0012_auto_20210311_2027.py diff --git a/main/migrations/0012_auto_20210311_2027.py b/main/migrations/0012_auto_20210311_2027.py new file mode 100644 index 0000000..113e51e --- /dev/null +++ b/main/migrations/0012_auto_20210311_2027.py @@ -0,0 +1,29 @@ +# Generated by Django 3.1.6 on 2021-03-11 17:27 + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ('main', '0011_auto_20210311_1734'), + ] + + operations = [ + migrations.RemoveField( + model_name='rolechangelogs', + name='name', + ), + migrations.CreateModel( + name='UnassignedTicket', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('ticket_id', models.IntegerField(help_text='Номер тикера, для которого сняли ответственного')), + ('status', models.IntegerField(choices=[(0, 'Снят с пользователя, перенесён в буферную группу'), (1, 'Авторство восстановлено'), (2, 'Пока нас не было, тикет испарился из буферной группы. Дополнительные действия не требуются')], default=0)), + ('assignee', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='tickets', to=settings.AUTH_USER_MODEL)), + ], + ), + ] diff --git a/main/models.py b/main/models.py index 95d38f2..4811e8d 100644 --- a/main/models.py +++ b/main/models.py @@ -33,9 +33,20 @@ class RoleChangeLogs(models.Model): """Модель для логирования изменений ролей пользователя""" user = models.ForeignKey(to=User, on_delete=models.CASCADE, help_text='Пользователь, которому присвоили другую роль') - name = models.TextField(help_text='Имя пользователя') old_role = models.IntegerField(default=0, help_text='Старая роль') new_role = models.IntegerField(default=0, help_text='Присвоенная роль') change_time = models.DateTimeField(help_text='Дата и время изменения роли') changed_by = models.ForeignKey(to=User, on_delete=models.CASCADE, related_name='changed_by', help_text='Кем была изменена роль') + + +class UnassignedTicketStatus(models.IntegerChoices): + UNASSIGNED = 0, 'Снят с пользователя, перенесён в буферную группу' + RESTORED = 1, 'Авторство восстановлено' + NOT_FOUND = 2, 'Пока нас не было, тикет испарился из буферной группы. Дополнительные действия не требуются' + + +class UnassignedTicket(models.Model): + assignee = models.ForeignKey(to=User, on_delete=models.CASCADE, related_name='tickets') + ticket_id = models.IntegerField(help_text='Номер тикера, для которого сняли ответственного') + status = models.IntegerField(choices=UnassignedTicketStatus.choices, default=UnassignedTicketStatus.UNASSIGNED) From d2e76fdbd96e6b84980d1b11de85fd923cb43129 Mon Sep 17 00:00:00 2001 From: Andrew Smirnov Date: Thu, 11 Mar 2021 20:54:56 +0300 Subject: [PATCH 2/7] Update model, add documentation todos, add sampla code for logging. --- main/extra_func.py | 33 +++++++++++++++++++--- main/migrations/0013_auto_20210311_2040.py | 18 ++++++++++++ main/models.py | 6 ++-- main/views.py | 7 +++-- 4 files changed, 55 insertions(+), 9 deletions(-) create mode 100644 main/migrations/0013_auto_20210311_2040.py diff --git a/main/extra_func.py b/main/extra_func.py index b76eb55..d2f1810 100644 --- a/main/extra_func.py +++ b/main/extra_func.py @@ -6,7 +6,7 @@ from zenpy import Zenpy from zenpy.lib.exception import APIException from access_controller.settings import ZENDESK_ROLES as ROLES, ONE_DAY -from main.models import UserProfile, RoleChangeLogs +from main.models import UserProfile, RoleChangeLogs, UnassignedTicket, UnassignedTicketStatus class ZendeskAdmin: @@ -128,16 +128,41 @@ def update_role(user_profile: UserProfile, role: str) -> UserProfile: def make_engineer(user_profile: UserProfile) -> UserProfile: """ - Функция **make_engineer** устанавливапет пользователю роль инженера. + Функция **make_engineer** устанавливает пользователю роль инженера. """ + update_role(user_profile, ROLES['engineer']) -def make_light_agent(user_profile: UserProfile) -> UserProfile: +def make_light_agent(user_profile: UserProfile, who_changes: User) -> UserProfile: """ - Функция **make_light_agent** устанавливапет пользователю роль легкого агента. + Функция **make_light_agent** устанавливапет пользователю роль легкого агента. + + .. todo:: + Решить проблему с ошибкой при выполнении этой функции из-за неотвязанных тикетов. А именно: + + - найти все тикеты, ответственным которых является снимаемый аккаунт + - для всех этих тикетов - перенести ответственность на буферную группу. + - [PARTIALY DONE] создать записи о снятых тикетах и их прошлом авторстве. Если тикет уже был закрыт - выставить в логе CLOSED. Иначе UNASSIGNED + - [DONE] после этого снять права c инженера + - [DONE] создать запись в логе о снятии прав инженера """ + + # tickets = [] + # # TODO: set ticket fields correct + # for ticket in tickets: + # UnassignedTicket.create( + # assignee=user_profile.user, + # ticket_id=ticket.number, + # status=UnassignedTicketStatus.UNASSIGNED if ticket.status=='opened' else UnassignedTicketStatus.CLOSED + # ) update_role(user_profile, ROLES['light_agent']) + RoleChangeLogs.create( + user=user_profile.user, + old_role=ROLES['engineer'], + new_role=ROLES['light_agent'], + changed_by=who_changes + ) def get_users_list() -> list: diff --git a/main/migrations/0013_auto_20210311_2040.py b/main/migrations/0013_auto_20210311_2040.py new file mode 100644 index 0000000..5648813 --- /dev/null +++ b/main/migrations/0013_auto_20210311_2040.py @@ -0,0 +1,18 @@ +# Generated by Django 3.1.6 on 2021-03-11 17:40 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('main', '0012_auto_20210311_2027'), + ] + + operations = [ + migrations.AlterField( + model_name='unassignedticket', + name='status', + field=models.IntegerField(choices=[(0, 'Снят с пользователя, перенесён в буферную группу'), (1, 'Авторство восстановлено'), (2, 'Пока нас не было, тикет испарился из буферной группы. Дополнительные действия не требуются'), (3, 'Тикет уже был закрыт. Дополнительные действия не требуются')], default=0), + ), + ] diff --git a/main/models.py b/main/models.py index 4811e8d..087784c 100644 --- a/main/models.py +++ b/main/models.py @@ -2,6 +2,7 @@ from django.db import models from django.contrib.auth.models import User from django.db.models.signals import post_save from django.dispatch import receiver +from django.utils import timezone class UserProfile(models.Model): @@ -12,7 +13,7 @@ class UserProfile(models.Model): ('has_control_access', 'Can view admin page'), ) - user = models.OneToOneField(to=User, on_delete=models.CASCADE, help_text='Пользователь') + user = models.OneToOneField(to=User, on_delete=models.CASCADE, help_text='Пользователь', related_name='user') role = 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='Имя пользователя на нашем сайте') @@ -35,7 +36,7 @@ class RoleChangeLogs(models.Model): help_text='Пользователь, которому присвоили другую роль') old_role = models.IntegerField(default=0, help_text='Старая роль') new_role = models.IntegerField(default=0, help_text='Присвоенная роль') - change_time = models.DateTimeField(help_text='Дата и время изменения роли') + change_time = models.DateTimeField(help_text='Дата и время изменения роли', default=timezone.now) changed_by = models.ForeignKey(to=User, on_delete=models.CASCADE, related_name='changed_by', help_text='Кем была изменена роль') @@ -44,6 +45,7 @@ class UnassignedTicketStatus(models.IntegerChoices): UNASSIGNED = 0, 'Снят с пользователя, перенесён в буферную группу' RESTORED = 1, 'Авторство восстановлено' NOT_FOUND = 2, 'Пока нас не было, тикет испарился из буферной группы. Дополнительные действия не требуются' + CLOSED = 3, 'Тикет уже был закрыт. Дополнительные действия не требуются' class UnassignedTicket(models.Model): diff --git a/main/views.py b/main/views.py index 36365f2..4c596ad 100644 --- a/main/views.py +++ b/main/views.py @@ -190,9 +190,10 @@ class AdminPageView(LoginRequiredMixin, PermissionRequiredMixin, FormView): def make_engineers(users): [make_engineer(user) for user in users] - @staticmethod - def make_light_agents(users): - [make_light_agent(user) for user in users] + def make_light_agents(self, users): + for user in users: + make_light_agent(user, self.request.user) + @staticmethod def count_users(users) -> tuple: From a430ee871d20439a1a885e526285d65fdc16a706 Mon Sep 17 00:00:00 2001 From: Sokurov Idar Date: Sun, 14 Mar 2021 17:13:41 +0300 Subject: [PATCH 3/7] Add ticket unassignment(exclude solved tickets) --- access_controller/settings.py | 6 ++ main/extra_func.py | 73 ++++++++++--------- ...312_1225.py => 0014_auto_20210314_1455.py} | 10 ++- main/views.py | 20 ++--- 4 files changed, 59 insertions(+), 50 deletions(-) rename main/migrations/{0012_auto_20210312_1225.py => 0014_auto_20210314_1455.py} (61%) diff --git a/access_controller/settings.py b/access_controller/settings.py index deadf32..953d2f6 100644 --- a/access_controller/settings.py +++ b/access_controller/settings.py @@ -183,4 +183,10 @@ ZENDESK_ROLES = { 'light_agent': 360005208980, } +ZENDESK_GROUPS = { + 'employees': 'Поддержка', + 'buffer': 'Сменная группа', +} + ONE_DAY = 12 # Количество часов в 1 рабочем дне + diff --git a/main/extra_func.py b/main/extra_func.py index 3583867..c7946fc 100644 --- a/main/extra_func.py +++ b/main/extra_func.py @@ -5,7 +5,7 @@ from django.contrib.auth.models import User from zenpy import Zenpy from zenpy.lib.exception import APIException -from access_controller.settings import ZENDESK_ROLES as ROLES, ONE_DAY +from access_controller.settings import ZENDESK_ROLES as ROLES, ONE_DAY, ZENDESK_GROUPS from main.models import UserProfile, RoleChangeLogs, UnassignedTicket, UnassignedTicketStatus @@ -29,12 +29,6 @@ class ZendeskAdmin: email: str = os.getenv('ACCESS_CONTROLLER_API_EMAIL') token: str = os.getenv('ACCESS_CONTROLLER_API_TOKEN') password: str = os.getenv('ACCESS_CONTROLLER_API_PASSWORD') - _instance = None - - def __new__(cls, *args, **kwargs): - if cls._instance is None: - cls._instance = super().__new__(cls) - return cls._instance def __init__(self): self.create_admin() @@ -82,6 +76,12 @@ class ZendeskAdmin: """ return self.admin.users.search(email).values[0] + def get_group(self, name): + groups = self.admin.search(name) + for group in groups: + return group + return None + def get_user_org(self, email: str) -> str: """ Функция **get_user_org** возвращает организацию, к которой относится пользователь по его email @@ -126,43 +126,42 @@ def update_role(user_profile: UserProfile, role: str) -> UserProfile: zendesk.admin.users.update(user) -def make_engineer(user_profile: UserProfile) -> UserProfile: +def make_engineer(user_profile: UserProfile, who_changes: User) -> UserProfile: """ Функция **make_engineer** устанавливает пользователю роль инженера. """ - + RoleChangeLogs.objects.create( + user=user_profile.user, + old_role=user_profile.custom_role_id, + new_role=ROLES['engineer'], + changed_by=who_changes + ) update_role(user_profile, ROLES['engineer']) def make_light_agent(user_profile: UserProfile, who_changes: User) -> UserProfile: """ Функция **make_light_agent** устанавливапет пользователю роль легкого агента. - - .. todo:: - Решить проблему с ошибкой при выполнении этой функции из-за неотвязанных тикетов. А именно: - - - найти все тикеты, ответственным которых является снимаемый аккаунт - - для всех этих тикетов - перенести ответственность на буферную группу. - - [PARTIALY DONE] создать записи о снятых тикетах и их прошлом авторстве. Если тикет уже был закрыт - выставить в логе CLOSED. Иначе UNASSIGNED - - [DONE] после этого снять права c инженера - - [DONE] создать запись в логе о снятии прав инженера """ + tickets = get_ticket_list(user_profile.user.email) + for ticket in tickets: + if ticket.status=='solved': + continue + UnassignedTicket.objects.create( + assignee=user_profile.user, + ticket_id=ticket.id, + status=UnassignedTicketStatus.UNASSIGNED + ) + ticket.group = ZendeskAdmin().get_group(ZENDESK_GROUPS['buffer']) + ZendeskAdmin().admin.tickets.update(ticket) - # tickets = [] - # # TODO: set ticket fields correct - # for ticket in tickets: - # UnassignedTicket.create( - # assignee=user_profile.user, - # ticket_id=ticket.number, - # status=UnassignedTicketStatus.UNASSIGNED if ticket.status=='opened' else UnassignedTicketStatus.CLOSED - # ) - update_role(user_profile, ROLES['light_agent']) - RoleChangeLogs.create( + RoleChangeLogs.objects.create( user=user_profile.user, - old_role=ROLES['engineer'], + old_role=user_profile.custom_role_id, new_role=ROLES['light_agent'], changed_by=who_changes ) + update_role(user_profile, ROLES['light_agent']) def get_users_list() -> list: @@ -175,9 +174,13 @@ def get_users_list() -> list: return zendesk.admin.organizations.users(org) +def get_ticket_list(email): + return ZendeskAdmin().admin.search(assignee=email, type='ticket') + + def update_profile(user_profile: UserProfile) -> UserProfile: """ - Функция обновляет профиль пользователя в соотвтетствии с текущим в Zendesk + Функция обновляет профиль пользователя в соотвтетствии с текущим в Zendesk """ user = ZendeskAdmin().get_user(user_profile.user.email) user_profile.name = user.name @@ -189,7 +192,7 @@ def update_profile(user_profile: UserProfile) -> UserProfile: def check_user_exist(email: str) -> bool: """ - Функция проверяет, существует ли пользователь + Функция проверяет, существует ли пользователь """ return ZendeskAdmin().check_user(email) @@ -241,9 +244,9 @@ class StatisticData: self.warnings = list() self.data = dict() self.statistic = dict() - self._set_data() + self._init_data() if stat is None: - self._set_statistic() + self._init_statistic() else: self.statistic = stat @@ -346,7 +349,7 @@ class StatisticData: return False return True - def _set_data(self): + def _init_data(self): """ Получение логов в диапазоне дат start_date-end_date для пользователя с почтой email """ @@ -361,7 +364,7 @@ class StatisticData: except User.DoesNotExist: self.errors += ['Пользователь не найден'] - def _set_statistic(self): + def _init_statistic(self): """ Функция заполняет словарь, в котором ключ - дата, значение - кол-во проработанных в этот день секунд """ diff --git a/main/migrations/0012_auto_20210312_1225.py b/main/migrations/0014_auto_20210314_1455.py similarity index 61% rename from main/migrations/0012_auto_20210312_1225.py rename to main/migrations/0014_auto_20210314_1455.py index 6d33580..77db2ec 100644 --- a/main/migrations/0012_auto_20210312_1225.py +++ b/main/migrations/0014_auto_20210314_1455.py @@ -1,12 +1,13 @@ -# Generated by Django 3.1.6 on 2021-03-12 09:25 +# Generated by Django 3.1.6 on 2021-03-14 11:55 from django.db import migrations, models +import django.utils.timezone class Migration(migrations.Migration): dependencies = [ - ('main', '0011_auto_20210311_1734'), + ('main', '0013_auto_20210311_2040'), ] operations = [ @@ -15,6 +16,11 @@ class Migration(migrations.Migration): name='custom_role_id', field=models.IntegerField(default=0, help_text='Код роли пользователя'), ), + migrations.AlterField( + model_name='rolechangelogs', + name='change_time', + field=models.DateTimeField(default=django.utils.timezone.now, help_text='Дата и время изменения роли'), + ), migrations.AlterField( model_name='userprofile', name='role', diff --git a/main/views.py b/main/views.py index 4c596ad..221e693 100644 --- a/main/views.py +++ b/main/views.py @@ -1,6 +1,5 @@ import logging import os -from datetime import datetime from django.contrib.auth.decorators import login_required from django.contrib.auth.forms import PasswordResetForm @@ -19,11 +18,12 @@ from django_registration.views import RegistrationView from zenpy import Zenpy from zenpy.lib.api_objects import User as ZenpyUser -from access_controller.settings import EMAIL_HOST_USER, ZENDESK_ROLES +from access_controller.settings import EMAIL_HOST_USER, ZENDESK_ROLES, ZENDESK_GROUPS from main.extra_func import check_user_exist, update_profile, get_user_organization, make_engineer, make_light_agent, \ - get_users_list, StatisticData + get_users_list, StatisticData, get_ticket_list, ZendeskAdmin from main.forms import AdminPageUsers, CustomRegistrationForm, CustomAuthenticationForm, StatisticForm -from .models import UserProfile +from .models import UserProfile, UnassignedTicket, UnassignedTicketStatus + class CustomRegistrationView(RegistrationView): """ @@ -106,12 +106,7 @@ def profile_page(request: WSGIRequest) -> HttpResponse: def auth_user(request): - admin_creds = { - 'email': os.environ.get('ACCESS_CONTROLLER_API_EMAIL'), - 'subdomain': 'ngenix1612197338', - 'token': os.environ.get('ACCESS_CONTROLLER_API_TOKEN'), - } - admin = Zenpy(**admin_creds) + admin = ZendeskAdmin().admin zenpy_user: ZenpyUser = admin.users.search(request.user.email).values[0] return zenpy_user, admin @@ -163,7 +158,7 @@ def work_become_engineer(request): def main_page(request): """ - Отображение логгирования на главной странице + Отображение логгирования на главной странице """ logger = logging.getLogger('main.index') logger.info('Index page opened') @@ -178,7 +173,7 @@ class AdminPageView(LoginRequiredMixin, PermissionRequiredMixin, FormView): def form_valid(self, form: AdminPageUsers) -> AdminPageUsers: """ - Функция установки ролей пользователям + Функция установки ролей пользователям """ if 'engineer' in self.request.POST: self.make_engineers(form.cleaned_data['users']) @@ -194,7 +189,6 @@ class AdminPageView(LoginRequiredMixin, PermissionRequiredMixin, FormView): for user in users: make_light_agent(user, self.request.user) - @staticmethod def count_users(users) -> tuple: """ From 0cc788c039a5263309bbf54798748ef280ffc2fa Mon Sep 17 00:00:00 2001 From: Sokurov Idar Date: Sun, 14 Mar 2021 17:26:41 +0300 Subject: [PATCH 4/7] minor fix --- main/extra_func.py | 1 + 1 file changed, 1 insertion(+) diff --git a/main/extra_func.py b/main/extra_func.py index c7946fc..0e0c0ed 100644 --- a/main/extra_func.py +++ b/main/extra_func.py @@ -152,6 +152,7 @@ def make_light_agent(user_profile: UserProfile, who_changes: User) -> UserProfil ticket_id=ticket.id, status=UnassignedTicketStatus.UNASSIGNED ) + ticket.assignee = None ticket.group = ZendeskAdmin().get_group(ZENDESK_GROUPS['buffer']) ZendeskAdmin().admin.tickets.update(ticket) From 5ec2407211bea13b147c0d24b00036914ca388d0 Mon Sep 17 00:00:00 2001 From: Sokurov Idar Date: Wed, 17 Mar 2021 09:35:15 +0300 Subject: [PATCH 5/7] Add ticket unassignment --- access_controller/settings.py | 2 +- main/extra_func.py | 35 +++++++++++++++++++++++------------ main/models.py | 1 + main/views.py | 12 ++++++------ 4 files changed, 31 insertions(+), 19 deletions(-) diff --git a/access_controller/settings.py b/access_controller/settings.py index 953d2f6..3a2d7df 100644 --- a/access_controller/settings.py +++ b/access_controller/settings.py @@ -187,6 +187,6 @@ ZENDESK_GROUPS = { 'employees': 'Поддержка', 'buffer': 'Сменная группа', } - +SOLVED_TICKETS_EMAIL = 'd.krikov@ngenix.net' ONE_DAY = 12 # Количество часов в 1 рабочем дне diff --git a/main/extra_func.py b/main/extra_func.py index 0e0c0ed..b601a03 100644 --- a/main/extra_func.py +++ b/main/extra_func.py @@ -2,10 +2,11 @@ import os from datetime import timedelta, datetime, date from django.contrib.auth.models import User +from django.utils import timezone from zenpy import Zenpy from zenpy.lib.exception import APIException -from access_controller.settings import ZENDESK_ROLES as ROLES, ONE_DAY, ZENDESK_GROUPS +from access_controller.settings import ZENDESK_ROLES as ROLES, ONE_DAY, ZENDESK_GROUPS, SOLVED_TICKETS_EMAIL from main.models import UserProfile, RoleChangeLogs, UnassignedTicket, UnassignedTicketStatus @@ -143,17 +144,18 @@ def make_light_agent(user_profile: UserProfile, who_changes: User) -> UserProfil """ Функция **make_light_agent** устанавливапет пользователю роль легкого агента. """ - tickets = get_ticket_list(user_profile.user.email) + tickets = get_tickets_list(user_profile.user.email) for ticket in tickets: - if ticket.status=='solved': - continue UnassignedTicket.objects.create( assignee=user_profile.user, ticket_id=ticket.id, - status=UnassignedTicketStatus.UNASSIGNED + status=UnassignedTicketStatus.SOLVED if ticket.status == 'solved' else UnassignedTicketStatus.UNASSIGNED ) - ticket.assignee = None - ticket.group = ZendeskAdmin().get_group(ZENDESK_GROUPS['buffer']) + if ticket.status == 'solved': + ticket.assignee = ZendeskAdmin().get_user(SOLVED_TICKETS_EMAIL) + else: + ticket.assignee = None + ticket.group = ZendeskAdmin().get_group(ZENDESK_GROUPS['buffer']) ZendeskAdmin().admin.tickets.update(ticket) RoleChangeLogs.objects.create( @@ -167,7 +169,7 @@ def make_light_agent(user_profile: UserProfile, who_changes: User) -> UserProfil def get_users_list() -> list: """ - Функция **get_users_list** возвращает список пользователей Zendesk, относящихся к организации. + Функция **get_users_list** возвращает список пользователей Zendesk, относящихся к организации. """ zendesk = ZendeskAdmin() admin = zendesk.get_user(zendesk.email) @@ -175,7 +177,10 @@ def get_users_list() -> list: return zendesk.admin.organizations.users(org) -def get_ticket_list(email): +def get_tickets_list(email): + """ + Функция возвращает список тикетов пользователя Zendesk + """ return ZendeskAdmin().admin.search(assignee=email, type='ticket') @@ -381,9 +386,15 @@ class StatisticData: if last_log.new_role == ROLES['engineer']: self.fill_daterange(last_log.change_time.date() + timedelta(days=1), self.end_date + timedelta(days=1)) - self.statistic[last_log.change_time.date()] += (timedelta(days=1) - get_timedelta(last_log)).total_seconds() - if self.end_date == datetime.now().date(): - self.statistic[self.end_date] = get_timedelta(None, datetime.now().time()).total_seconds() + 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) + ).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() for log_index in range(len(self.data) - 1): if self.data[log_index].new_role == ROLES['engineer']: diff --git a/main/models.py b/main/models.py index b202977..7bd76bb 100644 --- a/main/models.py +++ b/main/models.py @@ -47,6 +47,7 @@ class UnassignedTicketStatus(models.IntegerChoices): RESTORED = 1, 'Авторство восстановлено' NOT_FOUND = 2, 'Пока нас не было, тикет испарился из буферной группы. Дополнительные действия не требуются' CLOSED = 3, 'Тикет уже был закрыт. Дополнительные действия не требуются' + SOLVED = 4, 'Тикет решён. Записан на пользователя с почтой SOLVED_TICKETS_EMAIL' class UnassignedTicket(models.Model): diff --git a/main/views.py b/main/views.py index 221e693..d014807 100644 --- a/main/views.py +++ b/main/views.py @@ -20,7 +20,7 @@ from zenpy.lib.api_objects import User as ZenpyUser from access_controller.settings import EMAIL_HOST_USER, ZENDESK_ROLES, ZENDESK_GROUPS from main.extra_func import check_user_exist, update_profile, get_user_organization, make_engineer, make_light_agent, \ - get_users_list, StatisticData, get_ticket_list, ZendeskAdmin + get_users_list, StatisticData, get_tickets_list, ZendeskAdmin from main.forms import AdminPageUsers, CustomRegistrationForm, CustomAuthenticationForm, StatisticForm from .models import UserProfile, UnassignedTicket, UnassignedTicketStatus @@ -181,9 +181,9 @@ class AdminPageView(LoginRequiredMixin, PermissionRequiredMixin, FormView): self.make_light_agents(form.cleaned_data['users']) return super().form_valid(form) - @staticmethod - def make_engineers(users): - [make_engineer(user) for user in users] + def make_engineers(self, users): + for user in users: + make_engineer(user, self.request.user) def make_light_agents(self, users): for user in users: @@ -227,8 +227,8 @@ class CustomLoginView(LoginView): @login_required() def statistic_page(request): - if not request.user.is_superuser: - return redirect('index') + if not request.user.has_perm('main.has_control_access'): + raise PermissionDenied context = { 'pagename': 'страница статистики', 'errors': list(), From b5c3a1219373350ed6cd3031302389dd01a10205 Mon Sep 17 00:00:00 2001 From: Sokurov Idar Date: Thu, 18 Mar 2021 20:07:21 +0300 Subject: [PATCH 6/7] minor fix --- main/extra_func.py | 1 - 1 file changed, 1 deletion(-) diff --git a/main/extra_func.py b/main/extra_func.py index b601a03..0224e01 100644 --- a/main/extra_func.py +++ b/main/extra_func.py @@ -381,7 +381,6 @@ class StatisticData: first_log, last_log = self.data[0], self.data[len(self.data) - 1] if first_log.old_role == ROLES['engineer']: - self.fill_daterange(self.start_date, first_log.change_time.date()) self.statistic[first_log.change_time.date()] += get_timedelta(first_log).total_seconds() if last_log.new_role == ROLES['engineer']: From 358351d6daf2539cff18602fef227908b5bc0388 Mon Sep 17 00:00:00 2001 From: Sokurov Idar Date: Thu, 18 Mar 2021 20:19:08 +0300 Subject: [PATCH 7/7] optimize imports --- main/extra_func.py | 6 +----- main/views.py | 25 ++++++++----------------- 2 files changed, 9 insertions(+), 22 deletions(-) diff --git a/main/extra_func.py b/main/extra_func.py index 81ccaf9..6ae7266 100644 --- a/main/extra_func.py +++ b/main/extra_func.py @@ -2,15 +2,11 @@ import os from datetime import timedelta, datetime, date from django.contrib.auth.models import User +from django.core.exceptions import ObjectDoesNotExist from django.utils import timezone from zenpy import Zenpy from zenpy.lib.exception import APIException -from main.models import UserProfile, RoleChangeLogs -from django.core.exceptions import ObjectDoesNotExist - - -from access_controller.settings import ZENDESK_ROLES as ROLES, ONE_DAY from access_controller.settings import ZENDESK_ROLES as ROLES, ONE_DAY, ZENDESK_GROUPS, SOLVED_TICKETS_EMAIL from main.models import UserProfile, RoleChangeLogs, UnassignedTicket, UnassignedTicketStatus diff --git a/main/views.py b/main/views.py index 406ed45..9f8a48a 100644 --- a/main/views.py +++ b/main/views.py @@ -1,7 +1,8 @@ import logging -import os +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 User, Permission from django.contrib.auth.tokens import default_token_generator from django.contrib.auth.views import LoginView @@ -13,29 +14,19 @@ from django.shortcuts import render, get_list_or_404, redirect from django.urls import reverse_lazy, reverse from django.views.generic import FormView from django_registration.views import RegistrationView -from django.contrib.auth.decorators import login_required -from django.contrib.auth.mixins import LoginRequiredMixin, PermissionRequiredMixin - -from zenpy import Zenpy +# Django REST +from rest_framework import viewsets +from rest_framework.response import Response from zenpy.lib.api_objects import User as ZenpyUser -from access_controller.settings import EMAIL_HOST_USER, ZENDESK_ROLES, ZENDESK_GROUPS -from main.extra_func import check_user_exist, update_profile, get_user_organization, make_engineer, make_light_agent, \ - get_users_list, StatisticData, get_tickets_list, ZendeskAdmin +from access_controller.settings import EMAIL_HOST_USER, ZENDESK_ROLES +from main.extra_func import ZendeskAdmin 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, \ StatisticData -from main.models import UserProfile from main.forms import AdminPageUsers, CustomRegistrationForm, CustomAuthenticationForm, StatisticForm -from .models import UserProfile, UnassignedTicket, UnassignedTicketStatus - - -from access_controller.settings import EMAIL_HOST_USER, ZENDESK_ROLES - -# Django REST -from rest_framework import viewsets, status from main.serializers import ProfileSerializer -from rest_framework.response import Response +from .models import UserProfile class CustomRegistrationView(RegistrationView):