import logging import os from datetime import datetime from django.contrib.auth.decorators import login_required 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.forms import PasswordResetForm 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, StatisticData, log from main.forms import AdminPageUsers, CustomRegistrationForm, CustomAuthenticationForm, StatisticForm from .models import UserProfile 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.custom_role_id = ZENDESK_ROLES['light_agent'] request.user.userprofile.save() log(request.user.userprofile) 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.custom_role_id = ZENDESK_ROLES['engineer'] request.user.userprofile.save() log(request.user.userprofile) 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(self, users): [make_engineer(user) for user in users] [log(user, self.request.user.userprofile) for user in users] # @staticmethod def make_light_agents(self, users): [make_light_agent(user) for user in users] [log(user, self.request.user.userprofile) 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': list(), } if request.method == "POST": form = StatisticForm(request.POST) if form.is_valid(): start_date, end_date = form.cleaned_data['range_start'], form.cleaned_data['range_end'] interval, show = form.cleaned_data['interval'], form.cleaned_data['display_format'] Data = StatisticData(start_date, end_date, form.cleaned_data['email']) Data.set_display(show) Data.set_interval(interval) stats = Data.get_statistic() if Data.errors: context['errors'] = Data.errors if Data.warnings: context['warnings'] = Data.warnings 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)