Update docs (views, extra_func, forms, models)
This commit is contained in:
parent
3443c60a5f
commit
1114c916e9
@ -11,6 +11,8 @@ https://docs.djangoproject.com/en/3.1/ref/settings/
|
||||
"""
|
||||
import os
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
from dotenv import load_dotenv
|
||||
|
||||
# Build paths inside the project like this: BASE_DIR / 'subdir'.
|
||||
|
@ -49,3 +49,33 @@ Views
|
||||
:members:
|
||||
|
||||
|
||||
*****************
|
||||
Обработка тикетов
|
||||
*****************
|
||||
|
||||
.. automodule:: main.requester
|
||||
:members:
|
||||
|
||||
|
||||
*********************
|
||||
Обработка статистики
|
||||
*********************
|
||||
|
||||
.. automodule:: main.statistic_data
|
||||
:members:
|
||||
|
||||
|
||||
*********************************
|
||||
Функционал администратора Zendesk
|
||||
*********************************
|
||||
|
||||
.. automodule:: main.zendesk_admin
|
||||
:members:
|
||||
|
||||
|
||||
********
|
||||
Тесты
|
||||
********
|
||||
|
||||
.. automodule:: main.tests
|
||||
:members:
|
||||
|
@ -12,10 +12,11 @@ def api_auth() -> dict:
|
||||
Функция создания пользователя с использованием Zendesk API.
|
||||
|
||||
Получает из env Zendesk - email, token, password пользователя.
|
||||
|
||||
Если данные валидны и пользователь Zendesk с указанным email и токеном или паролем существует,
|
||||
создается словарь данных пользователя, полученных через API c Zendesk.
|
||||
|
||||
:return: данные пользователя
|
||||
:return: данные пользователя в виде словаря: id, имя, email, роль, аватар
|
||||
"""
|
||||
credentials = {
|
||||
'subdomain': ACTRL_ZENDESK_SUBDOMAIN
|
||||
|
@ -1,9 +1,9 @@
|
||||
"""
|
||||
Вспомогательные функции со списками пользователей, статистикой и т.д.
|
||||
Вспомогательные функции.
|
||||
"""
|
||||
import logging
|
||||
from datetime import timedelta
|
||||
from typing import Union
|
||||
from typing import Union, Optional
|
||||
|
||||
from django.contrib.auth import get_user_model
|
||||
from django.core.exceptions import ObjectDoesNotExist
|
||||
@ -55,7 +55,8 @@ def make_light_agent(user_profile: UserProfile, who_changes: get_user_model()) -
|
||||
Функция устанавливает пользователю роль легкого агента.
|
||||
|
||||
:param user_profile: Профиль пользователя
|
||||
:return: Вызов функции **update_role** с параметрами: профиль пользователя, роль "light_agent"
|
||||
:return: Вызов функции **update_role** с параметрами: профиль пользователя, роль "light_agent".
|
||||
Предварительно снимаем тикеты, находящие в работы у пользователя.
|
||||
"""
|
||||
tickets: SearchResultGenerator = get_tickets_list(user_profile.user.email)
|
||||
ticket: ZenpyTicket
|
||||
@ -85,7 +86,7 @@ def make_light_agent(user_profile: UserProfile, who_changes: get_user_model()) -
|
||||
|
||||
def get_users_list() -> list:
|
||||
"""
|
||||
Функция **get_users_list** возвращает список пользователей Zendesk, относящихся к организации SYSTEM.
|
||||
Функция возвращает список пользователей Zendesk, относящихся к организации SYSTEM.
|
||||
"""
|
||||
zendesk = zenpy
|
||||
|
||||
@ -95,23 +96,29 @@ def get_users_list() -> list:
|
||||
return users
|
||||
|
||||
|
||||
def get_tickets_list(email) -> list:
|
||||
def get_tickets_list(email: str) -> Optional[list]:
|
||||
"""
|
||||
Функция возвращает список тикетов пользователя Zendesk
|
||||
Функция возвращает список тикетов пользователя Zendesk.
|
||||
|
||||
:param email: Email пользователя
|
||||
:return: Список тикетов пользователя
|
||||
"""
|
||||
return TicketListRequester().get_tickets_list_for_user(zenpy.get_user(email))
|
||||
|
||||
|
||||
def get_tickets_list_for_group(group_name):
|
||||
def get_tickets_list_for_group(group_name: str) -> Optional[list]:
|
||||
"""
|
||||
Функция возвращает список не назначенных, нерешённых тикетов группы Zendesk
|
||||
Функция возвращает список не назначенных, не решённых тикетов группы Zendesk.
|
||||
|
||||
:param group_name: Название группы пользователя
|
||||
:return: Список тикетов группы
|
||||
"""
|
||||
return TicketListRequester().get_tickets_list_for_group(zenpy.get_group(group_name))
|
||||
|
||||
|
||||
def update_profile(user_profile: UserProfile) -> None:
|
||||
"""
|
||||
Функция обновляет профиль пользователя в соответствии с текущим в Zendesk.
|
||||
Функция обновляет профиль пользователя в БД в соответствии с текущим в Zendesk.
|
||||
|
||||
:param user_profile: Профиль пользователя
|
||||
:return: Обновленный, в соответствие с текущими данными в Zendesk, профиль пользователя
|
||||
@ -148,6 +155,9 @@ def check_user_auth(email: str, password: str) -> bool:
|
||||
"""
|
||||
Функция проверяет, верны ли входные данные.
|
||||
|
||||
:param email: Email пользователя
|
||||
:param password: Пароль пользователя
|
||||
:return: Существует ли пользователь
|
||||
:raise: :class:`APIException`: исключение, вызываемое если пользователь не аутентифицирован
|
||||
"""
|
||||
creds = {
|
||||
@ -165,7 +175,7 @@ def check_user_auth(email: str, password: str) -> bool:
|
||||
|
||||
def update_user_in_model(profile: UserProfile, zendesk_user: ZenpyUser) -> None:
|
||||
"""
|
||||
Функция обновляет профиль пользователя при изменении данных пользователя на Zendesk.
|
||||
Функция обновляет профиль пользователя в модели при изменении данных пользователя на Zendesk.
|
||||
|
||||
:param profile: Профиль пользователя
|
||||
:param zendesk_user: Данные пользователя в Zendesk
|
||||
@ -181,7 +191,10 @@ def update_user_in_model(profile: UserProfile, zendesk_user: ZenpyUser) -> None:
|
||||
|
||||
def count_users(users: list) -> tuple:
|
||||
"""
|
||||
Функция подсчета количества сотрудников с ролями engineer и light_agent
|
||||
Функция подсчета количества сотрудников с ролями engineer и light_agent.
|
||||
|
||||
:param users: Список пользователей
|
||||
:return: Количество инженеров, количество light_agents
|
||||
"""
|
||||
engineers, light_agents = 0, 0
|
||||
for user in users:
|
||||
@ -194,7 +207,7 @@ def count_users(users: list) -> tuple:
|
||||
|
||||
def update_users_in_model() -> list:
|
||||
"""
|
||||
Обновляет пользователей в модели UserProfile по списку пользователей в организации
|
||||
Обновляет пользователей в модели UserProfile по списку пользователей в организации.
|
||||
"""
|
||||
users = get_users_list()
|
||||
for user in users:
|
||||
@ -253,7 +266,13 @@ class DatabaseHandler(logging.Handler):
|
||||
def __init__(self):
|
||||
logging.Handler.__init__(self)
|
||||
|
||||
def emit(self, record):
|
||||
def emit(self, record: logging.LogRecord) -> None:
|
||||
"""
|
||||
Функция записи в базу данных лога с изменением роли пользователя.
|
||||
|
||||
:param record: Лог смены роли пользователя
|
||||
:return: Запись в БД лога по смене роли пользователя с указанием новой и старой роли, а также автора изменения
|
||||
"""
|
||||
database = RoleChangeLogs()
|
||||
users = record.msg
|
||||
if users[1]:
|
||||
@ -284,7 +303,7 @@ class CsvFormatter(logging.Formatter):
|
||||
"""
|
||||
Функция форматирует запись смены роли пользователя в строку.
|
||||
|
||||
:param record: Запись смены роли пользователя.
|
||||
:param record: Лог смены роли пользователя.
|
||||
:return: Строка с записью смены пользователя.
|
||||
"""
|
||||
users = record.msg
|
||||
@ -307,7 +326,7 @@ class CsvFormatter(logging.Formatter):
|
||||
return msg
|
||||
|
||||
|
||||
def log(user, admin=None):
|
||||
def log(user: get_user_model(), admin: get_user_model() = None) -> None:
|
||||
"""
|
||||
Функция осуществляет запись логов в базу данных и csv файл.
|
||||
|
||||
@ -335,7 +354,7 @@ def set_session_params_for_work_page(request: WSGIRequest, count: int = None, is
|
||||
|
||||
:param request: Получение данных с рабочей страницы пользователя
|
||||
:param count: Количество запрошенных тикетов
|
||||
:param is_confirm: Назначение тикетов
|
||||
:param is_confirm: Назначены ли тикеты
|
||||
:return: Перезагрузка страницы "Управление правами" соответствующего пользователя
|
||||
"""
|
||||
request.session['is_confirm'] = is_confirm
|
||||
|
@ -1,5 +1,5 @@
|
||||
"""
|
||||
Формы.
|
||||
Формы, использующиеся в приложении.
|
||||
"""
|
||||
from django import forms
|
||||
from django.contrib.auth.forms import AuthenticationForm
|
||||
|
@ -13,7 +13,6 @@ from access_controller.settings import ZENDESK_ROLES
|
||||
class UserProfile(models.Model):
|
||||
"""
|
||||
Модель профиля пользователя.
|
||||
|
||||
Профиль создается и изменяется при создании и изменении модель User.
|
||||
"""
|
||||
|
||||
@ -31,11 +30,7 @@ class UserProfile(models.Model):
|
||||
@property
|
||||
def zendesk_role(self) -> str:
|
||||
"""
|
||||
Функция возвращает роль пользователя в Zendesk.
|
||||
|
||||
В формате str, либо UNDEFINED, если пользователь не найден
|
||||
|
||||
:return: Роль пользователя в Zendesk
|
||||
Роль пользователя в Zendesk, либо UNDEFINED, если пользователь не найден.
|
||||
"""
|
||||
for role, r_id in ZENDESK_ROLES.items():
|
||||
if r_id == self.custom_role_id:
|
||||
@ -44,12 +39,12 @@ class UserProfile(models.Model):
|
||||
|
||||
|
||||
@receiver(post_save, sender=get_user_model())
|
||||
def create_user_profile(instance, created, **kwargs) -> None:
|
||||
def create_user_profile(instance: get_user_model(), created: bool, **kwargs) -> None:
|
||||
"""
|
||||
Функция создания профиля пользователя (Userprofile) при регистрации пользователя.
|
||||
|
||||
:param instance: Экземпляр класса User
|
||||
:param created: Создание профиля пользователя
|
||||
:param created: Существует ли пользователь
|
||||
:param kwargs: Параметры
|
||||
:return: Обновленный список объектов профилей пользователей
|
||||
"""
|
||||
@ -58,7 +53,7 @@ def create_user_profile(instance, created, **kwargs) -> None:
|
||||
|
||||
|
||||
@receiver(post_save, sender=get_user_model())
|
||||
def save_user_profile(instance, **kwargs) -> None:
|
||||
def save_user_profile(instance: get_user_model(), **kwargs) -> None:
|
||||
"""
|
||||
Функция записи БД профиля пользователя.
|
||||
|
||||
@ -84,7 +79,7 @@ class RoleChangeLogs(models.Model):
|
||||
|
||||
class UnassignedTicketStatus(models.IntegerChoices):
|
||||
"""
|
||||
Класс статусов не распределенных тикетов.
|
||||
Модель статусов нераспределенных тикетов.
|
||||
|
||||
:param UNASSIGNED: Снят с пользователя, перенесён в буферную группу
|
||||
:param RESTORED: Авторство восстановлено
|
||||
@ -95,7 +90,7 @@ class UnassignedTicketStatus(models.IntegerChoices):
|
||||
"""
|
||||
UNASSIGNED = 0, 'Снят с пользователя, перенесён в буферную группу'
|
||||
RESTORED = 1, 'Авторство восстановлено'
|
||||
NOT_FOUND = 2, 'Пока нас не было, тикет испарился из ' \
|
||||
NOT_FOUND = 2, 'Пока нас не было, тикет был перенесен из ' \
|
||||
'буферной группы. Дополнительные действия не требуются'
|
||||
CLOSED = 3, 'Тикет уже был закрыт. Дополнительные действия не требуются'
|
||||
SOLVED = 4, 'Тикет решён. Записан на пользователя с почтой SOLVED_TICKETS_EMAIL'
|
||||
|
@ -1,6 +1,8 @@
|
||||
"""
|
||||
Обработка тикетов.
|
||||
Обработка тикетов, составление списков тикетов для пользователя и группы пользователей.
|
||||
"""
|
||||
from typing import Optional
|
||||
|
||||
import requests
|
||||
from zenpy import TicketApi
|
||||
from zenpy.lib.api_objects import Ticket
|
||||
@ -11,6 +13,13 @@ from main.zendesk_admin import zenpy
|
||||
class TicketListRequester:
|
||||
"""
|
||||
Класс обработки тикетов.
|
||||
|
||||
:param email: Email пользователя
|
||||
:type display: :class:`str`
|
||||
:param token_or_password: Токен или пароль
|
||||
:type display: :class:`str`
|
||||
:param prefix: Формат строка url страницы Zendesk
|
||||
:type display: :class:`str`
|
||||
"""
|
||||
def __init__(self):
|
||||
self.email = zenpy.credentials['email']
|
||||
@ -21,16 +30,22 @@ class TicketListRequester:
|
||||
self.token_or_password = zenpy.credentials.get('password')
|
||||
self.prefix = f'https://{zenpy.credentials.get("subdomain")}.zendesk.com/api/v2/'
|
||||
|
||||
def get_tickets_list_for_user(self, zendesk_user: zenpy) -> str:
|
||||
def get_tickets_list_for_user(self, zendesk_user: zenpy) -> Optional[list]:
|
||||
"""
|
||||
Функция получения списка тикетов пользователя Zendesk.
|
||||
|
||||
:param zendesk_user: Пользователь Zendesk
|
||||
:return: Список тикетов, назначенных на данного пользователя в Zendesk
|
||||
"""
|
||||
url = self.prefix + f'users/{zendesk_user.id}/tickets/assigned'
|
||||
return self._get_tickets(url)
|
||||
|
||||
def get_tickets_list_for_group(self, group: zenpy) -> list():
|
||||
def get_tickets_list_for_group(self, group: zenpy) -> Optional[list]:
|
||||
"""
|
||||
Функция получения списка тикетов группы пользователей Zendesk.
|
||||
|
||||
:param group: Название группы
|
||||
:return: Список тикетов
|
||||
"""
|
||||
url = self.prefix + '/tickets'
|
||||
all_tickets = self._get_tickets(url)
|
||||
@ -40,9 +55,12 @@ class TicketListRequester:
|
||||
tickets.append(ticket)
|
||||
return tickets
|
||||
|
||||
def _get_tickets(self, url: str) -> list():
|
||||
def _get_tickets(self, url: str) -> Optional[list]:
|
||||
"""
|
||||
Функция получения полного списка тикетов по url.
|
||||
|
||||
:param url: Url Zendesk c указанием тикетов, назначенных на пользователя
|
||||
:return: Список тикетов
|
||||
"""
|
||||
response = requests.get(url, auth=(self.email, self.token_or_password))
|
||||
tickets = []
|
||||
|
@ -1,5 +1,5 @@
|
||||
"""
|
||||
Сериализаторы.
|
||||
Сериализаторы, используемые в приложении.
|
||||
"""
|
||||
from django.contrib.auth import get_user_model
|
||||
from rest_framework import serializers
|
||||
|
@ -61,7 +61,7 @@ def setup_context(**kwargs) -> Dict[str, Any]:
|
||||
|
||||
class CustomRegistrationView(RegistrationView):
|
||||
"""
|
||||
Отображение и логика работы страницы регистрации пользователя.
|
||||
Класс отображения и логики работы страницы регистрации пользователя.
|
||||
|
||||
:param form_class: Форма, которую необходимо заполнить для регистрации
|
||||
:type form_class: :class:`forms.CustomRegistrationForm`
|
||||
@ -86,9 +86,12 @@ class CustomRegistrationView(RegistrationView):
|
||||
def register(self, form: CustomRegistrationForm) -> Optional[get_user_model()]:
|
||||
"""
|
||||
Функция регистрации пользователя.
|
||||
1. Ввод email пользователя, указанный на Zendesk
|
||||
|
||||
1. Ввод email пользователя, указанный на Zendesk.
|
||||
|
||||
2. В случае если пользователь с данным паролем зарегистрирован на Zendesk и относится к организации SYSTEM,
|
||||
происходит сброс ссылки с установлением пароля на указанный email
|
||||
происходит сброс ссылки с установлением пароля на указанный email.
|
||||
|
||||
3. Создается пользователь class User, а также его профиль.
|
||||
|
||||
:param form: Email пользователя на Zendesk
|
||||
@ -133,7 +136,7 @@ class CustomRegistrationView(RegistrationView):
|
||||
"""
|
||||
Функция дает разрешение на просмотр страница администратора, если пользователь имеет роль admin.
|
||||
|
||||
:param user: авторизованный пользователь (получает разрешение, имея роль "admin")
|
||||
:param user: Авторизованный пользователь (получает разрешение, имея роль "admin")
|
||||
"""
|
||||
if user.userprofile.role == 'admin':
|
||||
content_type = ContentType.objects.get_for_model(UserProfile)
|
||||
@ -148,8 +151,8 @@ class CustomRegistrationView(RegistrationView):
|
||||
Функция возвращает url-адрес страницы, куда нужно перейти после успешной/не успешной регистрации.
|
||||
Используется самой django-registration.
|
||||
|
||||
:param user: пользователь, пытающийся зарегистрироваться
|
||||
:return: адресация на страницу успешной регистрации
|
||||
:param user: Пользователь, пытающийся зарегистрироваться
|
||||
:return: Адресация на страницу успешной регистрации
|
||||
"""
|
||||
return self.urls[self.redirect_url]
|
||||
|
||||
@ -158,8 +161,8 @@ def registration_error(request: WSGIRequest) -> HttpResponse:
|
||||
"""
|
||||
Функция отображения страницы ошибки регистрации.
|
||||
|
||||
:param request: регистрация
|
||||
:return: адресация на страницу ошибки
|
||||
:param request: Регистрация
|
||||
:return: Адресация на страницу ошибки
|
||||
"""
|
||||
return render(request, 'django_registration/registration_error.html')
|
||||
|
||||
@ -169,8 +172,8 @@ def profile_page(request: WSGIRequest) -> HttpResponse:
|
||||
"""
|
||||
Функция отображения страницы профиля.
|
||||
|
||||
:param request: данные пользователя из БД
|
||||
:return: адресация на страницу пользователя
|
||||
:param request: Данные пользователя из БД
|
||||
:return: Адресация на страницу пользователя
|
||||
"""
|
||||
user_profile: UserProfile = request.user.userprofile
|
||||
update_profile(user_profile)
|
||||
@ -187,9 +190,9 @@ def work_page(request: WSGIRequest, required_id: int) -> HttpResponse:
|
||||
"""
|
||||
Функция отображения страницы "Управления правами" для текущего пользователя (login_required).
|
||||
|
||||
:param request: объект пользователя
|
||||
:param request: Объект пользователя
|
||||
:param id: id пользователя, используется для динамической адресации
|
||||
:return: адресация на страницу "Управления правами" (либо на страницу "Авторизации", если id и user.id не совпадают
|
||||
:return: Адресация на страницу "Управления правами" (либо на страницу "Авторизации", если id и user.id не совпадают
|
||||
"""
|
||||
users = get_users_list()
|
||||
if request.user.id == required_id:
|
||||
@ -227,8 +230,8 @@ def work_hand_over(request: WSGIRequest) -> HttpResponseRedirect:
|
||||
"""
|
||||
Функция позволяет текущему пользователю сдать права, а именно сменить в Zendesk роль с "engineer" на "light_agent"
|
||||
|
||||
:param request: данные текущего пользователя (login_required)
|
||||
:return: перезагрузка текущей страницы после выполнения смены роли
|
||||
:param request: Данные текущего пользователя (login_required)
|
||||
:return: Перезагрузка текущей страницы после выполнения смены роли
|
||||
"""
|
||||
make_light_agent(request.user.userprofile, request.user)
|
||||
return set_session_params_for_work_page(request)
|
||||
@ -240,8 +243,8 @@ def work_become_engineer(request: WSGIRequest) -> HttpResponseRedirect:
|
||||
Функция позволяет текущему пользователю получить права, а именно сменить в Zendesk роль с "light_agent"
|
||||
на "engineer".
|
||||
|
||||
:param request: данные текущего пользователя (login_required)
|
||||
:return: перезагрузка текущей страницы после выполнения смены роли
|
||||
:param request: Данные текущего пользователя (login_required)
|
||||
:return: Перезагрузка текущей страницы после выполнения смены роли
|
||||
"""
|
||||
make_engineer(request.user.userprofile, request.user)
|
||||
return set_session_params_for_work_page(request)
|
||||
@ -250,9 +253,10 @@ def work_become_engineer(request: WSGIRequest) -> HttpResponseRedirect:
|
||||
@login_required()
|
||||
def work_get_tickets(request: WSGIRequest) -> HttpResponse:
|
||||
"""
|
||||
Функция получения тикетов в работу.
|
||||
|
||||
:param request:
|
||||
:return:
|
||||
:param request: Запрос на принятие тикетов в работу
|
||||
:return: Перезагрузка рабочей страницы
|
||||
"""
|
||||
zenpy_user = zenpy.get_user(request.user.email)
|
||||
|
||||
@ -289,6 +293,8 @@ class AdminPageView(LoginRequiredMixin, PermissionRequiredMixin, SuccessMessageM
|
||||
:type form_class: :class:`forms.AdminPageUsersForm`
|
||||
:param success_url: Адрес страницы администратора
|
||||
:type success_url: :class:`HttpResponseRedirect`
|
||||
:param success_message: Уведомление об изменении прав
|
||||
:type success_url: :class:`str`
|
||||
"""
|
||||
permission_required = 'main.has_control_access'
|
||||
template_name = 'pages/adm_ruleset.html'
|
||||
@ -333,7 +339,12 @@ class AdminPageView(LoginRequiredMixin, PermissionRequiredMixin, SuccessMessageM
|
||||
|
||||
class CustomLoginView(LoginView):
|
||||
"""
|
||||
Отображение страницы авторизации пользователя
|
||||
Класс отображения страницы авторизации пользователя.
|
||||
|
||||
:param extra_context: Добавление в контекст статус пользователя "залогинен"
|
||||
:type extra_context: :class:`dict`
|
||||
:param form_class: Форма страницы авторизации
|
||||
:type form_class: :class: forms.CustomAuthenticationForm
|
||||
"""
|
||||
extra_context = setup_context(login_lit=True)
|
||||
form_class = CustomAuthenticationForm
|
||||
@ -353,7 +364,8 @@ class UsersViewSet(viewsets.ReadOnlyModelViewSet):
|
||||
|
||||
def list(self, request: WSGIRequest, *args, **kwargs) -> Response:
|
||||
"""
|
||||
Функция возвращает список пользователей, список пользователей Zendesk, количество engineers и light-agents.
|
||||
Функция возвращает список пользователей Zendesk, количество engineers и light-agents.
|
||||
|
||||
:param request: Запрос
|
||||
:param args: Аргументы
|
||||
:param kwargs: Параметры
|
||||
@ -376,6 +388,7 @@ class UsersViewSet(viewsets.ReadOnlyModelViewSet):
|
||||
def choose_users(zendesk: list, model: list) -> list:
|
||||
"""
|
||||
Функция формирует список пользователей, которые не зарегистрированы у нас.
|
||||
|
||||
:param zendesk: Список пользователей Zendesk
|
||||
:param model: Список пользователей (модель Userprofile)
|
||||
:return: Список
|
||||
@ -389,7 +402,8 @@ class UsersViewSet(viewsets.ReadOnlyModelViewSet):
|
||||
@staticmethod
|
||||
def get_zendesk_users(users: list) -> list:
|
||||
"""
|
||||
Получение списка пользователей Zendesk, не являющихся админами.
|
||||
Функция получения списка пользователей Zendesk, не являющихся админами.
|
||||
|
||||
:param users: Список пользователей
|
||||
:return: Список пользователей, не являющимися администраторами.
|
||||
"""
|
||||
@ -406,8 +420,8 @@ def statistic_page(request: WSGIRequest) -> HttpResponse:
|
||||
"""
|
||||
Функция отображения страницы статистики (для "superuser").
|
||||
|
||||
:param request: данные о пользователе: email, время и интервал работы. Данные получаем через forms.StatisticForm
|
||||
:return: адресация на страницу статистики
|
||||
:param request: Данные о пользователе: email, время и интервал работы. Данные получаем через forms.StFatisticForm
|
||||
:return: Адресация на страницу статистики
|
||||
"""
|
||||
|
||||
# if not request.user.has_perm('main.has_control_access'):
|
||||
|
@ -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:
|
||||
|
||||
(<word>,<pos>)
|
||||
|
||||
Where <word> is the word string found and <pos> is the position
|
||||
of the start of the word within the text.
|
||||
|
||||
The optional argument <valid_chars> 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()
|
Loading…
x
Reference in New Issue
Block a user