291 lines
12 KiB
Python
291 lines
12 KiB
Python
import logging
|
||
import os
|
||
from datetime import date, datetime
|
||
|
||
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
|
||
from django.contrib.contenttypes.models import ContentType
|
||
from django.core.exceptions import PermissionDenied
|
||
from django.core.handlers.wsgi import WSGIRequest
|
||
from django.http import HttpResponseRedirect, HttpResponse
|
||
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 zenpy import Zenpy
|
||
from zenpy.lib.api_objects import User as ZenpyUser
|
||
|
||
from access_controller.settings import EMAIL_HOST_USER, ZENDESK_ROLES
|
||
from main.extra_func import check_user_exist, update_profile, get_user_organization, make_engineer, make_light_agent, \
|
||
get_users_list, last_day_of_month, get_statistic_from_data, get_data_logs
|
||
from main.forms import AdminPageUsers, CustomRegistrationForm, CustomAuthenticationForm, StatisticForm
|
||
from .models import UserProfile
|
||
|
||
content_type_temp = ContentType.objects.get_for_model(UserProfile)
|
||
permission_temp, created = Permission.objects.get_or_create(
|
||
codename='has_control_access',
|
||
content_type=content_type_temp,
|
||
)
|
||
|
||
|
||
class CustomRegistrationView(RegistrationView):
|
||
"""
|
||
Отображение и логика работы страницы регистрации пользователя
|
||
|
||
1. Ввод email пользователя, указанный на Zendesk
|
||
2. В случае если пользователь с данным паролем зарегистрирован на Zendesk и относится к определенной организации, происходит сброс ссылки с установлением пароля на указанный email
|
||
3. Создается пользователь class User, а также его профиль
|
||
"""
|
||
form_class = CustomRegistrationForm
|
||
template_name = 'django_registration/registration_form.html'
|
||
success_url = reverse_lazy('django_registration_complete')
|
||
is_allowed = True
|
||
|
||
def register(self, form: CustomRegistrationForm) -> User:
|
||
self.is_allowed = True
|
||
if check_user_exist(form.data['email']) and get_user_organization(form.data['email']) == 'SYSTEM':
|
||
forms = PasswordResetForm(self.request.POST)
|
||
if forms.is_valid():
|
||
opts = {
|
||
'use_https': self.request.is_secure(),
|
||
'token_generator': default_token_generator,
|
||
'from_email': EMAIL_HOST_USER,
|
||
'email_template_name': 'registration/password_reset_email.html',
|
||
'subject_template_name': 'registration/password_reset_subject.txt',
|
||
'request': self.request,
|
||
'html_email_template_name': None,
|
||
'extra_email_context': None,
|
||
}
|
||
user = User.objects.create_user(
|
||
username=form.data['email'],
|
||
email=form.data['email'],
|
||
password=User.objects.make_random_password(length=50)
|
||
)
|
||
forms.save(**opts)
|
||
update_profile(user.userprofile)
|
||
self.set_permission(user)
|
||
return user
|
||
else:
|
||
raise ValueError('Непредвиденная ошибка')
|
||
else:
|
||
self.is_allowed = False
|
||
|
||
@staticmethod
|
||
def set_permission(user) -> None:
|
||
"""
|
||
Дает разрешение на просмотр страница администратора, если пользователь имеет роль admin
|
||
"""
|
||
if user.userprofile.role == 'admin':
|
||
content_type = ContentType.objects.get_for_model(UserProfile)
|
||
permission = Permission.objects.get(
|
||
codename='has_control_access',
|
||
content_type=content_type,
|
||
)
|
||
user.user_permissions.add(permission)
|
||
|
||
def get_success_url(self, user: User = None) -> success_url:
|
||
"""
|
||
Возвращает url-адрес страницы, куда нужно перейти после успешной/неуспешной регистрации
|
||
Используется самой django-registration
|
||
"""
|
||
if self.is_allowed:
|
||
return reverse_lazy('password_reset_done')
|
||
else:
|
||
return reverse_lazy('django_registration_disallowed')
|
||
|
||
|
||
@login_required()
|
||
def profile_page(request: WSGIRequest) -> HttpResponse:
|
||
"""
|
||
Отображение страницы профиля
|
||
"""
|
||
user_profile: UserProfile = request.user.userprofile
|
||
update_profile(user_profile)
|
||
context = {
|
||
'profile': user_profile,
|
||
'pagename': 'Страница профиля'
|
||
}
|
||
return render(request, 'pages/profile.html', context)
|
||
|
||
|
||
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)
|
||
zenpy_user: ZenpyUser = admin.users.search(request.user.email).values[0]
|
||
return zenpy_user, admin
|
||
|
||
|
||
@login_required()
|
||
def work_page(request, id):
|
||
users = get_users_list()
|
||
if request.user.id == id:
|
||
engineers = []
|
||
light_agents = []
|
||
for user in users:
|
||
|
||
if user.custom_role_id == ZENDESK_ROLES['engineer']:
|
||
engineers.append(user)
|
||
elif user.custom_role_id == ZENDESK_ROLES['light_agent']:
|
||
light_agents.append(user)
|
||
|
||
context = {
|
||
'engineers': engineers,
|
||
'agents': light_agents,
|
||
'pagename': 'Управление правами'
|
||
}
|
||
return render(request, 'pages/work.html', context)
|
||
return redirect("login")
|
||
|
||
|
||
@login_required()
|
||
def work_hand_over(request):
|
||
zenpy_user, admin = auth_user(request)
|
||
|
||
if zenpy_user.custom_role_id == ZENDESK_ROLES['engineer']:
|
||
zenpy_user.custom_role_id = ZENDESK_ROLES['light_agent']
|
||
admin.users.update(zenpy_user)
|
||
request.user.userprofile.role = "agent"
|
||
request.user.userprofile.save()
|
||
return HttpResponseRedirect(reverse('work', args=(request.user.id,)))
|
||
|
||
|
||
@login_required()
|
||
def work_become_engineer(request):
|
||
zenpy_user, admin = auth_user(request)
|
||
if zenpy_user.custom_role_id == ZENDESK_ROLES['light_agent']:
|
||
zenpy_user.custom_role_id = ZENDESK_ROLES['engineer']
|
||
admin.users.update(zenpy_user)
|
||
request.user.userprofile.role = "agent"
|
||
request.user.userprofile.save()
|
||
return HttpResponseRedirect(reverse('work', args=(request.user.id,)))
|
||
|
||
|
||
def main_page(request):
|
||
"""
|
||
Отображение логгирования на главной странице
|
||
"""
|
||
logger = logging.getLogger('main.index')
|
||
logger.info('Index page opened')
|
||
return render(request, 'pages/index.html')
|
||
|
||
|
||
class AdminPageView(LoginRequiredMixin, PermissionRequiredMixin, FormView):
|
||
permission_required = 'main.has_control_access'
|
||
template_name = 'pages/adm_ruleset.html'
|
||
form_class = AdminPageUsers
|
||
success_url = '/control/'
|
||
|
||
def form_valid(self, form: AdminPageUsers) -> AdminPageUsers:
|
||
"""
|
||
Функция установки ролей пользователям
|
||
"""
|
||
if 'engineer' in self.request.POST:
|
||
self.make_engineers(form.cleaned_data['users'])
|
||
elif 'light_agent' in self.request.POST:
|
||
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]
|
||
|
||
@staticmethod
|
||
def make_light_agents(users):
|
||
[make_light_agent(user) for user in users]
|
||
|
||
@staticmethod
|
||
def count_users(users) -> tuple:
|
||
"""
|
||
Функция подсчета количества сотрудников с ролями engineer и light_a
|
||
|
||
.. todo::
|
||
this func counts users from all zendesk instead of just from a model:
|
||
"""
|
||
engineers, light_agents = 0, 0
|
||
for user in users:
|
||
if user.custom_role_id == ZENDESK_ROLES['engineer']:
|
||
engineers += 1
|
||
elif user.custom_role_id == ZENDESK_ROLES['light_agent']:
|
||
light_agents += 1
|
||
return engineers, light_agents
|
||
|
||
def get_context_data(self, **kwargs) -> dict:
|
||
"""
|
||
Функция формирования контента страницы администратора (с проверкой прав доступа)
|
||
"""
|
||
if self.request.user.userprofile.role != 'admin':
|
||
raise PermissionDenied
|
||
context = super().get_context_data(**kwargs)
|
||
context['users'] = get_list_or_404(
|
||
UserProfile, role='agent')
|
||
context['engineers'], context['light_agents'] = self.count_users(get_users_list())
|
||
return context # TODO: need to get profile page url
|
||
|
||
|
||
class CustomLoginView(LoginView):
|
||
"""
|
||
Отображение страницы авторизации пользователя
|
||
"""
|
||
form_class = CustomAuthenticationForm
|
||
|
||
|
||
@login_required()
|
||
def statistic_page(request):
|
||
if not request.user.is_superuser:
|
||
return redirect('index')
|
||
context = {
|
||
'pagename': 'страница статистики',
|
||
'errors': [],
|
||
}
|
||
if request.method == "POST":
|
||
form = StatisticForm(request.POST)
|
||
if not form.is_valid():
|
||
context['errors'] += form.errors
|
||
else:
|
||
start_date, end_date, data = form.cleaned_data['range_start'], form.cleaned_data['range_end'], list()
|
||
if end_date < start_date or end_date > datetime.now().date():
|
||
context['errors'] += ['Конец диапазона должен быть позже начала диапазона и раньше текущего времени']
|
||
else:
|
||
data = get_data_logs(context, start_date, end_date, form.cleaned_data['email'])
|
||
stats = get_statistic_from_data(data, start_date, end_date)
|
||
if stats is None:
|
||
context['errors'] += ['Не найдено изменений роли в указаном диапазоне']
|
||
interval, show = form.cleaned_data['interval'], form.cleaned_data['display_format']
|
||
|
||
if not (show in ['hours', 'days']): # Работа с форматом отображения
|
||
context['errors'] += ['Формат отображения должен быть в часах или днях']
|
||
elif stats:
|
||
for key, item in stats.items():
|
||
if show == 'hours':
|
||
stats[key] = item / 3600
|
||
elif show == 'days':
|
||
stats[key] = item / 86400
|
||
|
||
if not (interval in ['days', 'months']): # Работа с интервалом работы
|
||
context['errors'] += ['Интервал работы должен быть в днях или месяцах']
|
||
elif interval == 'months' and stats: # Переделываем ключи под формат в прототипе(начало_месяца-конец_месяца)
|
||
new_stats = {}
|
||
for key, value in stats.items():
|
||
current_month_start = max(start_date, date(year=key.year, month=key.month, day=1))
|
||
current_month_end = min(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_stats.get(index):
|
||
new_stats[index] += value
|
||
else:
|
||
new_stats[index] = value
|
||
stats = new_stats
|
||
|
||
context['log_stats'] = stats if not context['errors'] else None
|
||
if request.method == 'GET':
|
||
form = StatisticForm()
|
||
context['form'] = form
|
||
return render(request, 'pages/stat.html', context)
|