diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..0d4799d --- /dev/null +++ b/.dockerignore @@ -0,0 +1,29 @@ +*.pyc +*.pyo +*.mo +*.db +*.css.map +*.egg-info +*.sql.gz +*.sqlite3 +.cache +.env +.project +.idea +.pydevproject +.idea/workspace.xml +.DS_Store +.git/ +.sass-cache +.vagrant/ +__pycache__ +dist +docs +env +logs +src/{{ project_name }}/settings/local.py +src/node_modules +web/media +web/static/CACHE +stats +Dockerfile diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..f86db45 --- /dev/null +++ b/.env.example @@ -0,0 +1,25 @@ +ACTRL_DEBUG=1 + +ACTRL_SECRET_KEY="v1i_fb\$_jf2#1v_lcsbu&eon4u-os0^px=s^iycegdycqy&5)6" +ACTRL_HOST="actrl.example.com" + +ACTRL_EMAIL_HOST="smtp.mail.ru" +ACTRL_EMAIL_PORT=2525 +ACTRL_EMAIL_TLS=1 +ACTRL_EMAIL_HOST_USER="djgr.02@mail.ru" +ACTRL_EMAIL_HOST_PASSWORD="djangogroup02" +ACTRL_FROM_EMAIL="djgr.02@mail.ru" +ACTRL_SERVER_EMAIL="djgr.02@mail.ru" + +ENG_CROLE_ID=360005209000 +LA_CROLE_ID=360005208980 +EMPL_GROUP="Поддержка" +BUF_GROUP="Сменная группа" +ST_EMAIL="d.krikov@ngenix.net" +LICENSE_NO=3 +SHIFTH=12 + +ACTRL_ZENDESK_SUBDOMAIN="ngenix1612197338" +ACTRL_API_EMAIL="email@example.com" +ACTRL_API_TOKEN="xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" +ACTRL_API_PASSWORD="" diff --git a/.gitignore b/.gitignore index 1f6ea85..2d1bab8 100644 --- a/.gitignore +++ b/.gitignore @@ -11,6 +11,7 @@ __pycache__/ local_settings.py db.sqlite3 db.sqlite3-journal +db/ media/ logs/ @@ -30,7 +31,6 @@ logs/ .Python build/ develop-eggs/ -dist/ downloads/ eggs/ .eggs/ diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..59c861e --- /dev/null +++ b/Dockerfile @@ -0,0 +1,10 @@ +FROM python:3.6 +COPY ./ /access_controller +WORKDIR /access_controller/ +RUN pip install -r requirements/prod.txt +RUN python manage.py makemigrations +EXPOSE 8000 +COPY start.sh /var/ +CMD bash /var/start.sh + + diff --git a/README.md b/README.md index 14e3869..eb66f37 100644 --- a/README.md +++ b/README.md @@ -39,37 +39,53 @@ ## Quickstart +Перед запуском требуется неообходимо `.env` файл. +```bash +cp .env.example .env +``` +Заменить переменные в `.env` на актуальные. ```bash sudo apt install make pip install --upgrade pip -pip install -r requirements.txt -./manage.py migrate -./manage.py loaddata data.json -./manage.py runserver +pip install -r requirements/dev.txt +(set -a && source .env && ./manage.py migrate) +(set -a && source .env && ./manage.py loaddata data.json) +(set -a && source .env && ./manage.py runserver) ``` -##ZenDesk Access Controller instruction for eng +## Перед запуском для тестирования: -##Перед запуском для тестирования: - -Убедитесь, что вы зарегистрированы в песочнице ZenDesk, у вас назначена организация (SYSTEM) +Убедитесь, что вы зарегистрированы в песочнице ZenDesk, у вас назначена организация `SYSTEM` Для админов ZenDesk дополнительно - создайте токен доступа в ZenDesk При запуске в Docker убедитесь что папка, которая будет служить хранилищем для БД, открыта на запись и чтение -##Запуск на локальной машине: - -скопировать репозиторий на локальную машину -перейти в папку приложения -активировать вирутальное окружение -выполнить команду pip install -r requirements.txt -в вирутальное окружение добавить следующие переменные : +## Запуск на локальной машине: +- Скопировать репозиторий на локальную машину +- Перейти в папку приложения +- Активировать виртуальное окружение +- Выполнить команду `pip install -r requirements/dev.txt` +- В виртуальное окружение добавить следующие переменные: -ACCESS_CONTROLLER_API_EMAIL={EMAIL} - почта админа в ZenDesk -ACCESS_CONTROLLER_API_PASSWORD={PASSWORD} - пароль админа ZenDesk -ACCESS_CONTROLLER_API_TOKEN={API_TOKEN} - API токен зендеск -ZD_DOMAIN={DOMAIN} - домен ZenDesk +``` +ACTRL_DEBUG={0/1} - включить режим дебага +ACTRL_HOST={HOSTNAME} - при запуске без дебага, надо указать домен на котором будет работать приложение +ACTRL_SECRET_KEY={DJANGO_SECRET_KEY} - секретный ключ сгенерированый Django + +ACTRL_EMAIL_HOST={SMTP_HOST} - домен почтового сервера через который приложение будет отправлять письма, например "smtp.gmail.com" +ACTRL_EMAIL_PORT={SMTP_PORT} - порт для почтового сервера, например 587, 465 , 2525 +ACTRL_EMAIL_TLS={USE_TLS} - использовать TLS для подключения к почтовому серверу, 0 или 1 +ACTRL_EMAIL_HOST_USER={USERNAME} - логин с которым приложение входит на почтовый сервер +ACTRL_EMAIL_HOST_PASSWORD={PASSWORD} - пароль/ключ с которым приложение входит на почтовый сервер +ACTRL_FROM_EMAIL={EMAIL} - адрес с которого приложение отправляет письма +ACTRL_SERVER_EMAIL={EMAIL} - адрес на который отвечают пользователя + +ACTRL_API_EMAIL={EMAIL} - почта админа в ZenDesk +ACTRL_API_PASSWORD={PASSWORD} - пароль админа ZenDesk +ACTRL_API_TOKEN={API_TOKEN} - API токен зендеск +ACTRL_ZENDESK_SUBDOMAIN={DOMAIN} - домен ZenDesk + ENG_CROLE_ID={ENGINEER_CUSTOM_ROLE_ID} - id роли инженера( custom_role_id сотрдника смены) LA_CROLE_ID={LIGHT_AGENT_CUSTOM_ROLE_ID} - id роли легкого агента (custom_role_id роли -легкий агент) EMPL_GROUP={EMPLOYEE_GROUP_NAME} - имя группы которой принадлежат сотрудники ССКС @@ -77,48 +93,62 @@ BUF_GROUP={BUFFER_GROUP_NAME} - имя буферной группы для пе ST_EMAIL={SOLVED_TICKETS_EMAIL} - почта на которую будут переназначятся закрытые тикеты LICENSE_NO={LICENSE_NO} - количество лицензий, отображаемых как доступные в приложении SHIFTH={SHIFT_HOURS} - количество часов в рабочей смене (нужно для статистики, пока не реализовано но требует указания значения) +``` + +- Выполнить команду `python manage.py migrate` +- Запустить приложение командой `python manage.py runserver` (можно указать в параметрах для файла manage.py) +- Перейти по ссылке в консоли (вероятнее всего откроется по адресу http://127.0.0.1:8000/) -выполнить команду python manage.py makemigrations -выполнить команду python manage.py migrate -запустить приложение командой python manage.py runserver (можно указать в параметрах для файла manage.py) -перейти по ссылке в консоли (вероятнее всего откроется по адресу http://127.0.0.1:8000/) +## Запуск в Docker: +Требуется установленный и настроенный Docker + +- Скопировать репозиторий на локальную машину +- В командной строке перейти в папку проекта +- Выполнить команду `docker build --tag access_controller:latest .` +- Выполнить команду +```bash +docker run -d -p 8000:8000 \ + ACTRL_DEBUG={0/1} \ + ACTRL_HOST={HOSTNAME} \ + ACTRL_SECRET_KEY={DJANGO_SECRET_KEY} \ + ACTRL_EMAIL_HOST={SMTP_HOST} \ + ACTRL_EMAIL_PORT={SMTP_PORT} \ + ACTRL_EMAIL_TLS={USE_TLS} \ + ACTRL_EMAIL_HOST_USER={USERNAME} \ + ACTRL_EMAIL_HOST_PASSWORD={PASSWORD} \ + ACTRL_FROM_EMAIL={EMAIL} \ + ACTRL_SERVER_EMAIL={EMAIL} \ + ACTRL_API_EMAIL={EMAIL} \ + ACTRL_API_PASSWORD={PASSWORD} \ + ACTRL_API_TOKEN={API_TOKEN} \ + ACTRL_ZENDESK_SUBDOMAIN={DOMAIN} \ + ENG_CROLE_ID={ENGINEER_CUSTOM_ROLE_ID} \ + LA_CROLE_ID={LIGHT_AGENT_CUSTOM_ROLE_ID} \ + EMPL_GROUP={EMPLOYEE_GROUP_NAME} \ + BUF_GROUP={BUFFER_GROUP_NAME} \ + ST_EMAIL={SOLVED_TICKETS_EMAIL} \ + LICENSE_NO={LICENSE_NO} \ + SHIFTH={SHIFT_HOURS} \ + -v {ABSOLUTE_PATH_TO_DB}:/zendesk-access-controller/db \ + access_controller:latest +``` +- открываем запущеный контейнер в браузере (можно перейти по ссылке http://localhost:8000/) -##Запуск в Docker: -Требуется установленный и настроеный Docker +## Запуск с тестовыми юзерами: +На локальной машине - перед запуском команды `python manage.py runserver` выполнить команду `python manage.py loaddata data.json` +Это создаст тестового админа и тестового пользователя в приложении для песочницы ZenDesk. -скопировать репозиторий на локальную машину -в командной строке перейти в папку проекта -выполнить команду docker build . -выполнить команду docker images (нам нужен id созданного образа) -выполнить команду docker run -d -p 8000:8000 -e ACCESS_CONTROLLER_API_EMAIL={EMAIL} -e ACCESS_CONTROLLER_API_PASSWORD={PASSWORD} -...(перечисляем все параметры виртуального окружени разделяя их -e) -v {абсолютный путь к папке, в которой будет размещена база}:/zendesk-access-controller/db {id образа докера} -открываем запущеный контейнер в браузере (можно перейти по ссылке http://localhost:8000/) +- Админ - `admin@gmail.com` / `zendeskadmin` +- Пользователь - `123@test.ru` / `zendeskuser` + +Не сработает если домен песочницы отличается от `ngenix1612197338` (на другом домене нужно будет создать сначала пользователей в песочнице с правами админа и легкого агента +с этими же почтами, назначить им организацию `SYSTEM`) -##Запуск с тестовыми юзерами: - -На локальной машине - перед запуском команды python manage.py runserver выполнить команду python manage.py loaddata data.json -Это создаст тестового админа и тестового пользователя в приложении для песочницы ZenDesk. Админ - admin@gmail.com / zendeskadmin , пользователь - 123@test.ru / zendeskuser . -Не сработает если домен песочницы отличается от ngenix1612197338 (на другом домене нужно будет создать сначала пользователей в песочнице с правами админа и легкого агента -с этими же почтами, назначить им организацию (SYSTEM)) - - -##Параметры тестовой песочницы: - -ACCESS_CONTROLLER_API_EMAIL={EMAIL} - почта админа в ZenDesk - взять у роководителя(если вы не админ) -ACCESS_CONTROLLER_API_PASSWORD={PASSWORD} - пароль админа ZenDesk - взять у роководителя(если вы не админ) -ACCESS_CONTROLLER_API_TOKEN={API_TOKEN} - API токен зендеск - взять у роководителя(если вы не админ) -ZD_DOMAIN=ngenix1612197338 -ENG_CROLE_ID=360005209000 -LA_CROLE_ID=360005208980 -EMPL_GROUP=Поддержка -BUF_GROUP=Сменная группа -ST_EMAIL=d.krikov@ngenix.net - -LICENSE_NO=3 -SHIFTH=12 +## Параметры тестовой песочницы: +Пример полной конфигурации можно найти в [.env.example](.env.example). Почту и токен админа ZenDesk взять у руководителя (если вы не админ). ## Read more diff --git a/access_controller/settings.py b/access_controller/settings.py index f9b5119..a7585ed 100644 --- a/access_controller/settings.py +++ b/access_controller/settings.py @@ -19,12 +19,16 @@ BASE_DIR = Path(__file__).resolve().parent.parent # See https://docs.djangoproject.com/en/3.1/howto/deployment/checklist/ # SECURITY WARNING: keep the secret key used in production secret! -SECRET_KEY = 'v1i_fb$_jf2#1v_lcsbu&eon4u-os0^px=s^iycegdycqy&5)6' +SECRET_KEY = os.getenv('ACTRL_SECRET_KEY','empty') # SECURITY WARNING: don't run with debug turned on in production! -DEBUG = True +DEBUG = bool(int(os.getenv('ACTRL_DEBUG',1))) -ALLOWED_HOSTS = ['127.0.0.1'] +ALLOWED_HOSTS = [ + '127.0.0.1', + 'localhost', + os.getenv('ACTRL_HOST'), +] # Application definition @@ -53,13 +57,13 @@ MIDDLEWARE = [ ROOT_URLCONF = 'access_controller.urls' EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend' -EMAIL_HOST = 'smtp.gmail.com' -EMAIL_PORT = 587 -EMAIL_USE_TLS = True -EMAIL_HOST_USER = 'group02django@gmail.com' -EMAIL_HOST_PASSWORD = 'djangogroup02' -DEFAULT_FROM_EMAIL = EMAIL_HOST_USER -SERVER_EMAIL = EMAIL_HOST_USER +EMAIL_HOST = os.getenv('ACTRL_EMAIL_HOST','smtp.gmail.com') +EMAIL_PORT = int(os.getenv('ACTRL_EMAIL_PORT',587)) +EMAIL_USE_TLS = bool(int(os.getenv('ACTRL_EMAIL_TLS',1))) +EMAIL_HOST_USER = os.getenv('ACTRL_EMAIL_HOST_USER','group02django@gmail.com') +EMAIL_HOST_PASSWORD = os.getenv('ACTRL_EMAIL_HOST_PASSWORD','djangogroup02') +DEFAULT_FROM_EMAIL = os.getenv('ACTRL_FROM_EMAIL',EMAIL_HOST_USER) +SERVER_EMAIL = os.getenv('ACTRL_SERVER_EMAIL',EMAIL_HOST_USER) TEMPLATES = [ { @@ -87,7 +91,7 @@ WSGI_APPLICATION = 'access_controller.wsgi.application' DATABASES = { 'default': { 'ENGINE': 'django.db.backends.sqlite3', - 'NAME': BASE_DIR / 'db.sqlite3', + 'NAME': BASE_DIR / 'db' / 'zd_db.sqlite3' } } @@ -146,18 +150,18 @@ AUTHENTICATION_BACKENDS = [ ZENDESK_ROLES = { - 'engineer': 360005209000, - 'light_agent': 360005208980, + 'engineer': int(os.getenv('ENG_CROLE_ID',0)), + 'light_agent': int(os.getenv('LA_CROLE_ID',0)), } ZENDESK_GROUPS = { - 'employees': 'Поддержка', - 'buffer': 'Сменная группа', + 'employees': os.getenv('EMPL_GROUP'), + 'buffer': os.getenv('BUF_GROUP'), } -SOLVED_TICKETS_EMAIL = 'd.krikov@ngenix.net' +SOLVED_TICKETS_EMAIL = os.getenv('ST_EMAIL') -ZENDESK_MAX_AGENTS = 3 +ZENDESK_MAX_AGENTS = int(os.getenv('LICENSE_NO',0)) REST_FRAMEWORK = { # Use Django's standard `django.contrib.auth` permissions, @@ -167,4 +171,9 @@ REST_FRAMEWORK = { ] } -ONE_DAY = 12 # Количество часов в 1 рабочем дне +ONE_DAY = int(os.getenv('SHIFTH',0)) # Количество часов в 1 рабочем дне + +ACTRL_ZENDESK_SUBDOMAIN = os.getenv('ACTRL_ZENDESK_SUBDOMAIN') or os.getenv('ZD_DOMAIN') +ACTRL_API_EMAIL = os.getenv('ACTRL_API_EMAIL') or os.getenv('ACCESS_CONTROLLER_API_EMAIL') +ACTRL_API_TOKEN = os.getenv('ACTRL_API_TOKEN') or os.getenv('ACCESS_CONTROLLER_API_TOKEN') +ACTRL_API_PASSWORD = os.getenv('ACTRL_API_PASSWORD') or os.getenv('ACCESS_CONTROLLER_API_PASSWORD') diff --git a/access_controller/urls.py b/access_controller/urls.py index f6a6754..63dc19f 100644 --- a/access_controller/urls.py +++ b/access_controller/urls.py @@ -14,6 +14,7 @@ Including another URLconf 2. Add a URL to urlpatterns: path('blog/', include('blog.urls')) """ from django.contrib import admin +from django.contrib.auth import views from django.urls import path, include from main.views import main_page, profile_page, CustomRegistrationView, CustomLoginView, registration_error @@ -36,8 +37,7 @@ urlpatterns = [ path('accounts/', include('django_registration.backends.activation.urls')), path('control/', AdminPageView.as_view(), name='control'), path('statistic/', statistic_page, name='statistic'), - ] - +] # Django REST urlpatterns += [ diff --git a/data.json b/data.json index 97678f3..a4310a4 100644 --- a/data.json +++ b/data.json @@ -1,7 +1,7 @@ [ { "model": "auth.user", - "pk": 3, + "pk": 1, "fields": { "password": "pbkdf2_sha256$216000$gHBBCr1jBELf$ZkEDW3IEd8Wij7u8vkv+0Eze32CS01bcaYWhcD9OIC4=", "last_login": null, @@ -19,16 +19,16 @@ }, { "model": "main.userprofile", - "pk": 3, + "pk": 1, "fields": { "name": "ZendeskAdmin", - "user": 3, + "user": 1, "role": "admin" } }, { "model": "auth.user", - "pk": 4, + "pk": 2, "fields": { "password": "pbkdf2_sha256$216000$5qLJgrm2Quq9$KDBNNymVZXkUx0HKBPFst2m83kLe0egPBnkW7KnkORU=", "last_login": null, @@ -46,10 +46,10 @@ }, { "model": "main.userprofile", - "pk": 4, + "pk": 2, "fields": { "name": "UserForAccessTest", - "user": 4, + "user": 2, "role": "agent", "custom_role_id": "360005209000" } diff --git a/media/.gitkeep b/db/.gitkeep similarity index 100% rename from media/.gitkeep rename to db/.gitkeep diff --git a/layouts/registration_success/registration_success.png b/layouts/registration_success/registration_success.png new file mode 100644 index 0000000..67e7074 Binary files /dev/null and b/layouts/registration_success/registration_success.png differ diff --git a/layouts/work/workv2.png b/layouts/work/workv2.png new file mode 100644 index 0000000..620ddb1 Binary files /dev/null and b/layouts/work/workv2.png differ diff --git a/main/apiauth.py b/main/apiauth.py index c24e85f..08a018c 100644 --- a/main/apiauth.py +++ b/main/apiauth.py @@ -3,6 +3,8 @@ import os from zenpy import Zenpy from zenpy.lib.api_objects import User as ZenpyUser +from access_controller.settings import ACTRL_ZENDESK_SUBDOMAIN, ACTRL_API_EMAIL, ACTRL_API_TOKEN, ACTRL_API_PASSWORD + def api_auth() -> dict: """ @@ -15,15 +17,15 @@ def api_auth() -> dict: :return: данные пользователя """ credentials = { - 'subdomain': 'ngenix1612197338' + 'subdomain': ACTRL_ZENDESK_SUBDOMAIN } - email = os.getenv('ACCESS_CONTROLLER_API_EMAIL') - token = os.getenv('ACCESS_CONTROLLER_API_TOKEN') - password = os.getenv('ACCESS_CONTROLLER_API_PASSWORD') + email = ACTRL_API_EMAIL + token = ACTRL_API_TOKEN + password = ACTRL_API_PASSWORD if email is None: raise ValueError('access_controller email not in env') - credentials['email'] = os.getenv('ACCESS_CONTROLLER_API_EMAIL') + credentials['email'] = email # prefer token, use password if token not provided if token: diff --git a/main/extra_func.py b/main/extra_func.py index 27986c8..0c93ba1 100644 --- a/main/extra_func.py +++ b/main/extra_func.py @@ -1,144 +1,19 @@ import logging -import os from datetime import timedelta, datetime, date +from typing import Optional from django.contrib.auth.models import User from django.core.exceptions import ObjectDoesNotExist +from django.shortcuts import redirect from django.utils import timezone from zenpy import Zenpy from zenpy.lib.exception import APIException +from zenpy.lib.api_objects import User as ZenpyUser, Ticket as ZenpyTicket +from zenpy.lib.generator import SearchResultGenerator - -from access_controller.settings import ZENDESK_ROLES as ROLES, ONE_DAY, ZENDESK_GROUPS, SOLVED_TICKETS_EMAIL +from access_controller.settings import ZENDESK_ROLES as ROLES, ONE_DAY, ACTRL_ZENDESK_SUBDOMAIN from main.models import UserProfile, RoleChangeLogs, UnassignedTicket, UnassignedTicketStatus - - -class ZendeskAdmin: - """ - Класс **ZendeskAdmin** существует, чтобы в каждой функции отдельно не проверять аккаунт администратора. - - :param credentials: Полномочия (первым указывается учетная запись организации в Zendesk) - :type credentials: :class:`dict` - :param email: Email администратора, указанный в env - :type email: :class:`str` - :param token: Токен администратора (формируется в Zendesk, указывается в env) - :type token: :class:`str` - :param password: Пароль администратора, указанный в env - :type password: :class:`str` - """ - - credentials: dict = { - 'subdomain': 'ngenix1612197338' - } - email: str = os.getenv('ACCESS_CONTROLLER_API_EMAIL') - token: str = os.getenv('ACCESS_CONTROLLER_API_TOKEN') - password: str = os.getenv('ACCESS_CONTROLLER_API_PASSWORD') - - def __init__(self): - self.create_admin() - - def check_user(self, email: str) -> bool: - """ - Функция осуществляет проверку существования пользователя в Zendesk по email. - - :param email: Email пользователя - :return: Является ли зарегистрированным - """ - return True if self.admin.search(email, type='user') else False - - def get_user_name(self, email: str) -> str: - """ - Функция **get_user_name** возвращает имя пользователя по его email - """ - user = self.admin.users.search(email).values[0] - return user.name - - def get_user_role(self, email: str) -> str: - """ - Функция возвращает роль пользователя по его email. - - :param email: Email пользователя - :return: Роль пользователя - """ - user = self.admin.users.search(email).values[0] - return user.role - - def get_user_id(self, email: str) -> str: - """ - Функция возвращает id пользователя по его email - - :param email: Email пользователя - :return: ID пользователя - """ - user = self.admin.users.search(email).values[0] - return user.id - - def get_user_image(self, email: str) -> str: - """ - Функция возвращает url-ссылку на аватар пользователя по его email. - - :param email: Email пользователя - :return: Аватар пользователя - """ - user = self.admin.users.search(email).values[0] - return user.photo['content_url'] if user.photo else None - - def get_user(self, email: str): - """ - Функция возвращает пользователя (объект) по его email. - - :param email: Email пользователя - :return: Объект пользователя, найденного в БД - """ - return self.admin.users.search(email).values[0] - - def get_group(self, name: str) -> str: - """ - Функция возвращает группу по названию - - :param name: Имя пользователя - :return: Группы пользователя (в случае отсутствия None) - """ - groups = self.admin.search(name, type='group') - for group in groups: - return group - return None - - def get_user_org(self, email: str) -> str: - """ - Функция возвращает организацию, к которой относится пользователь по его email. - - :param email: Email пользователя - :return: Организация пользователя - """ - user = self.admin.users.search(email).values[0] - return user.organization.name if user.organization else None - - def create_admin(self) -> None: - """ - Функция создает администратора, проверяя наличие вводимых данных в env. - - :param credentials: В список полномочий администратора вносятся email, token, password из env - :type credentials: :class:`dict` - :raise: :class:`ValueError`: исключение, вызываемое если email не введен в env - :raise: :class:`APIException`: исключение, вызываемое если пользователя с таким email не существует в Zendesk - """ - - if self.email is None: - raise ValueError('access_controller email not in env') - self.credentials['email'] = self.email - - if self.token: - self.credentials['token'] = self.token - elif self.password: - self.credentials['password'] = self.password - else: - raise ValueError('access_controller token or password not in env') - self.admin = Zenpy(**self.credentials) - try: - self.admin.search(self.email, type='user') - except APIException: - raise ValueError('invalid access_controller`s login data') +from main.zendesk_admin import zenpy def update_role(user_profile: UserProfile, role: int) -> None: @@ -149,7 +24,7 @@ def update_role(user_profile: UserProfile, role: int) -> None: :param role: Новая роль :return: Пользователь с обновленной ролью """ - zendesk = ZendeskAdmin() + zendesk = zenpy user = zendesk.get_user(user_profile.user.email) user.custom_role_id = role user_profile.custom_role_id = role @@ -174,7 +49,8 @@ def make_light_agent(user_profile: UserProfile, who_changes: User) -> None: :param user_profile: Профиль пользователя :return: Вызов функции **update_role** с параметрами: профиль пользователя, роль "light_agent" """ - tickets = get_tickets_list(user_profile.user.email) + tickets: SearchResultGenerator = get_tickets_list(user_profile.user.email) + ticket: ZenpyTicket for ticket in tickets: UnassignedTicket.objects.create( assignee=user_profile.user, @@ -182,19 +58,30 @@ def make_light_agent(user_profile: UserProfile, who_changes: User) -> None: status=UnassignedTicketStatus.SOLVED if ticket.status == 'solved' else UnassignedTicketStatus.UNASSIGNED ) if ticket.status == 'solved': - ticket.assignee = ZendeskAdmin().get_user(SOLVED_TICKETS_EMAIL) + ticket.assignee_id = zenpy.solved_tickets_user_id else: ticket.assignee = None - ticket.group = ZendeskAdmin().get_group(ZENDESK_GROUPS['buffer']) - ZendeskAdmin().admin.tickets.update(ticket) - update_role(user_profile, ROLES['light_agent']) + ticket.group_id = zenpy.buffer_group_id + + if tickets.count: + zenpy.admin.tickets.update(tickets.values) + + attempts, success = 5, False + while not success and attempts != 0: + try: + update_role(user_profile, ROLES['light_agent']) + success = True + except APIException as e: + attempts -= 1 + if attempts == 0: + raise e def get_users_list() -> list: """ Функция **get_users_list** возвращает список пользователей Zendesk, относящихся к организации SYSTEM. """ - zendesk = ZendeskAdmin() + zendesk = zenpy # У пользователей должна быть организация SYSTEM org = next(zendesk.admin.search(type='organization', name='SYSTEM')) @@ -206,17 +93,17 @@ def get_tickets_list(email): """ Функция возвращает список тикетов пользователя Zendesk """ - return ZendeskAdmin().admin.search(assignee=email, type='ticket') + return zenpy.admin.search(assignee=email, type='ticket') -def update_profile(user_profile: UserProfile) -> UserProfile: +def update_profile(user_profile: UserProfile): """ Функция обновляет профиль пользователя в соответствии с текущим в Zendesk. :param user_profile: Профиль пользователя :return: Обновленный, в соответствие с текущими данными в Zendesk, профиль пользователя """ - user = ZendeskAdmin().get_user(user_profile.user.email) + user = zenpy.get_user(user_profile.user.email) user_profile.name = user.name user_profile.role = user.role user_profile.custom_role_id = user.custom_role_id if user.custom_role_id else 0 @@ -231,7 +118,7 @@ def check_user_exist(email: str) -> bool: :param email: Email пользователя :return: Зарегистрирован ли пользователь в Zendesk """ - return ZendeskAdmin().check_user(email) + return zenpy.check_user(email) def get_user_organization(email: str) -> str: @@ -241,7 +128,7 @@ def get_user_organization(email: str) -> str: :param email: Email пользователя :return: Организация пользователя """ - return ZendeskAdmin().get_user_org(email) + return zenpy.get_user_org(email) def check_user_auth(email: str, password: str) -> bool: @@ -253,7 +140,7 @@ def check_user_auth(email: str, password: str) -> bool: creds = { 'email': email, 'password': password, - 'subdomain': 'ngenix1612197338', + 'subdomain': ACTRL_ZENDESK_SUBDOMAIN, } try: user = Zenpy(**creds) @@ -263,7 +150,7 @@ def check_user_auth(email: str, password: str) -> bool: return True -def update_user_in_model(profile: UserProfile, zendesk_user: User): +def update_user_in_model(profile: UserProfile, zendesk_user: ZenpyUser): """ Функция обновляет профиль пользователя при изменении данных пользователя на Zendesk. @@ -435,7 +322,7 @@ class StatisticData: self.display = display_format return True - def get_data(self) -> list: + def get_data(self) -> Optional[dict]: """ Функция возвращает данные - список объектов RoleChangeLogs. """ @@ -665,3 +552,13 @@ def log(user, admin=0): logger.addHandler(csvhandler) logger.setLevel('INFO') logger.info(users) + + +def set_session_params_for_work_page(request, count=None, is_confirm=True): + """ + Функция для страницы получения прав + Устанавливает данные сессии о успешности запроса и количестве назначенных тикетов + """ + request.session['is_confirm'] = is_confirm + request.session['count_tickets'] = count + return redirect('work', request.user.id) diff --git a/main/forms.py b/main/forms.py index 22bd76b..81b2e8a 100644 --- a/main/forms.py +++ b/main/forms.py @@ -96,12 +96,11 @@ class StatisticForm(forms.Form): :type range_end: :class:`django.forms.fields.DateField` """ email = forms.EmailField( - label='Электроная почта', + label='Электронная почта', widget=forms.EmailInput( attrs={ 'placeholder': 'example@ngenix.ru', 'class': 'form-control', - 'style': 'background-color:#f2f2f2;' } ), ) diff --git a/main/models.py b/main/models.py index ac6f91c..1920c4d 100644 --- a/main/models.py +++ b/main/models.py @@ -81,3 +81,4 @@ 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='Статус тикета') + diff --git a/main/templates/base/menu.html b/main/templates/base/menu.html index 93799a5..ef5df18 100644 --- a/main/templates/base/menu.html +++ b/main/templates/base/menu.html @@ -15,21 +15,27 @@ {% else %} class="btn btn-secondary" {% endif %} - href="{% url 'profile' %}">Профиль + href="{% url 'profile' %}">Профиль {% if perms.main.has_control_access %} Управление + href="{% url 'control' %}">Управление + Статистика {% else %} Запрос прав + href="{% url 'work' request.user.id %}">Запрос прав {% endif %} Выйти @@ -40,13 +46,13 @@ {% else %} class="btn btn-secondary" {% endif %} - href="/accounts/login">Войти + href="/accounts/login">Войти Зарегистрироваться + href="/accounts/register">Зарегистрироваться {% endif %} diff --git a/main/templates/base/success_messages.html b/main/templates/base/success_messages.html deleted file mode 100644 index fdef313..0000000 --- a/main/templates/base/success_messages.html +++ /dev/null @@ -1,14 +0,0 @@ -
Свободных Мест: {{ licences_remaining }}
+Свободных Мест: